Skip to content

Instantly share code, notes, and snippets.

@pazteddy
Created July 12, 2023 01:24
Show Gist options
  • Select an option

  • Save pazteddy/8f588489766ec02faea39763e6e1e211 to your computer and use it in GitHub Desktop.

Select an option

Save pazteddy/8f588489766ec02faea39763e6e1e211 to your computer and use it in GitHub Desktop.
Associations, callbacks and validations

Associations

Task 1. Create models and tables

rails generate model User username email role critics_count:integer
rails g model Critic title body:text user:references
rails g model Company name description:text start_date:date country cover
rails g model Game name summary:text release_date:date category:integer rating:decimal cover
rails g model Platform name category:integer
rails g model Genre name
rails generate model InvolvedCompany company:references game:references developer:boolean publisher:boolean

Generando jointables

rails g migration CreateJoinTableGamePlatform game platform
rails g migration CreateJoinTableGameGenre game genre

Task 2. Create basic model associations

A Critic belongs to a user

belongs_to :user

A User has many critics

has_many :critics, dependent: :destroy

A Company has many involved_companies and has many games through involved_companies

class Company
  has_many :involved_companies, dependent: :destroy
  has_many :games, through: :involved_companies
end

An InvolvedCompany belongs to a company and belongs to a game

belongs_to :company
belongs_to :game

A Game has many involved_companies and has many companies through involved_companies

class Game
  has_many :involved_companies, dependent: :destroy
  has_many :companies, through: :involved_companies
end

A Game has and belongs to many platforms

class Game
  has_and_belongs_to_many :platforms
end

A Game has and belongs to many genres

class Game
  has_and_belongs_to_many :genres
end

A Platform has and belongs to many games

class Platform
  has_and_belongs_to_many :games
end

A Genre has and belongs to many games

class Genre
  has_and_belongs_to_many :games
end

Examples

User

user = User.create(username: "Teddy")
user.critics.create(title: "New title", body: "New Body")
user.critics.create(title: "New title 2", body: "New Body 2")
user.critics

Critics

testino = User.create(username: "testino")
testino.critics.create(title: 'New critic', body: 'New body')
testino = testino.critics
critic = testino.first
critic.user

Games

game = Game.create(name: "The last of us")
company = Company.create(name: "Nautghy Doog")
InvolvedCompany.create(developer: true, publisher: false, game: game, company: company)
action_genre = Genre.create(name: 'action')
game.genres.push(action_genre)
platform_playstation = Platform.create(name: 'PlayStation 4', category: 1)
buscaminas.platforms << platform_playstation

Self Joins

Task 3. Create a self join association

1. Create a migration to add the parent_id column making a :parent references

rails g migration AddParentRefToGame parent:references
def change
  add_reference :games, :parent, foreign_key: { to_table: :games }
end

2. Add new associations to Game model:

class Game
  has_many :expansions, class_name: "Game",
                      foreign_key: "parent_id",
                      dependent: :destroy,
                      inverse_of: "parent"

  belongs_to :parent, class_name: "Game", optional: true
end

Polymorphic Associations

Task 4. Create a polymorphic association

1.Create a migration to add a polymorphic reference criticable on the table critics.

rails g migration AddCriticableToCritics criticable:references{polymorphic}

Add the polymorphic relationships to the models: Critic, Game and Company

class Critic
  ...
  belongs_to :criticable, polymorphic: true
end
class Game
  ...
  has_many :critics, as: :criticable, dependent: :destroy
end

class Company
  ...
  has_many :critics, as: :criticable, dependent: :destroy
end

Enums fields

Task 5. Creating Enums Game and Platform

rails g migration AddDefaultCategoryToGames
class AddDefaultCategoryToGames < ActiveRecord::Migration[7.0]
  def change
    change_column_default(:games, :category, from:nil , to: 0)
  end
end
class Game
  enum category: { main_game: 0, expansion: 1 }
end

Platform

rails g migration AddDefaultCategoryToPlatform
class AddDefaultCategoryToPlatform < ActiveRecord::Migration[7.0]
  def change
    change_column_default(:platforms, :category, from:nil , to: 0)
  end
end
class Platform
  ...
  enum category: {
    console: 0,
    arcade: 1,
    platform: 2,
    operating_system: 3,
    portable_console: 4,
    computer: 5
  }
end

Active Record Callbacks

Task 1. Create a callback to count critics

Tenemos que adicionar un valor por defecto a critics_count, mediante una migración:

rails g migration AddDefaultCountToUser
class AddDefaultCountToUser < ActiveRecord::Migration[7.0]
  def change
    change_column_default(:users, :critics_count, from:nil , to: 0)
  end
end

En el modelo Critic adicionamos nuestros callbacks

class Critic
  ...
  after_create :increment_critics_count
  after_destroy :decrement_critics_count

  private

  def increment_critics_count
    critic_user = user
    critic_user.critics_count += 1
    critic_user.save
  end

  def decrement_critics_count
    critic_user = user
    critic_user.critics_count -= 1
    critic_user.save
  end
end

Belongs_to association magic: counter_cache

En el modelo Critic hicimos el llamado a counter_cache

belongs_to :user, counter_cache: true

Validations and Seeds

Migraciones para poder añadir indices a valores unicos

rails g migration AddIndexColumnNameToModel column:type:uniq
rails g migration AddIndexNameToPlatform name:string:uniq
rails g migration AddIndexNameToGenre name:string:uniq
rails g migration AddIndexNameToCompany name:string:uniq
rails g migration AddUniquennesCompanyIdGameIdToInvolvedCompany
@celsodiaz
Copy link

Gran aporte Teddy!!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment