Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

has_many through additional attributes

How do we set additional parameters in has_many through associations?

Thanks. Neelesh

like image 820
Neelesh Avatar asked Mar 19 '11 17:03

Neelesh


3 Answers

This blog post has the perfect solution: http://www.tweetegy.com/2011/02/setting-join-table-attribute-has_many-through-association-in-rails-activerecord/

That solution is: create your ":through model" manually, rather than through the automated way when you append to its owner's array.

Using the example from that blog post. Where your models are:

class Product < ActiveRecord::Base
  has_many :collaborators
  has_many :users, :through => :collaborators
end

class User < ActiveRecord::Base
  has_many :collaborators
  has_many :products, :through => :collaborators
end

class Collaborator < ActiveRecord::Base
  belongs_to :product
  belongs_to :user
end

Previously you may have gone: product.collaborators << current_user.

However, to set the additional argument (in this example is_admin), rather than the automated way of appending to the array, you can do it manually like:

product.save && product.collaborators.create(:user => current_user, :is_admin => true)

This approach allows you to set the additional arguments at save-time. NB. the product.save is necessary if the model hasn't yet been saved, otherwise it can be omitted.

like image 148
William Denniss Avatar answered Oct 22 '22 22:10

William Denniss


has_many :tags, :through => :post_tags, :conditions => ['tag.owner_id = ?' @owner.id]
like image 30
Unixmonkey Avatar answered Oct 22 '22 22:10

Unixmonkey


Well I was in a similar situation where I wanted to have a join table that joined 3 models. But I wanted the third model ID to be gotten from the second model.

class Ingredient < ActiveRecord::Base

end

class Person < ActiveRecord::Base
  has_many :food
  has_many :ingredients_food_person
  has_many :ingredients, through: :ingredients_food_person
end

class Food
  belongs_to :person
  has_many :ingredient_food_person
  has_many :ingredients, through: :ingredients_food_person

  before_save do
    ingredients_food_person.each { |ifp| ifp.person_id = person_id }
  end
end

class IngredientFoodPerson < ActiveRecord::Base
  belongs_to :ingredient
  belongs_to :food
  belongs_to :person
end

And surprisingly, you can do something like this:

food = Food.new ingredients: [Ingredient.new, Ingredient.new]
food.ingredients_food_person.size # => 2
food.save

At first I thought that before I saved, I wouldn't have access to #ingredients_food_person after assigning #ingredients. But it generates the models automatically.

like image 1
Zequez Avatar answered Oct 22 '22 22:10

Zequez