Reputation: 8642
I have two models - "symbols" and "users". Among other attributes, symbols has "created_by_id" and "updated_by_id" attributes which are id's of users that created/updated a certain symbol entry.
Let's say I want to display the symbols table with their "symbol" attribute and the nested "created by" and "updated by" (user.username) attributes for each symbol entry. Resulting table should look something like this:
symbol created_by updated_by
------------------------------------
symbol1 username1 username2
symbol2 username1 username2
How can I achieve this? I guess I need accepts_nested_attributes_for :user
and probably has_one :user
(?) in my Symbol model. Do I also need belongs_to :user
in my User model?
After the models are set up properly, how can I access the username of users associated with "created_by_id" and "updated_by_id" in my view?
I have an edit form where I used nested form like this (which works fine):
<%= form_for @symbol do |f| %>
Symbol:
<%= f.text_field :symbol %>
<%= f.fields_for :kanji do |kf| %>
Meaning:
<%= kf.text_field :meaning %>
Onyomi:
<%= kf.text_field :onyomi %>
Kunyomi:
<%= kf.text_field :kunyomi %>
<% end %>
<%= f.submit "Save" %>
<% end %>
but I couldn't figure out how to do something similar in this case where I have two nested attributes associated with the same symbol.
I'm new to rails so perhaps I got the whole idea of how to do this wrong. If there is a better than what I just explained how I want to do it, please correct me.
edit: Here are the models. The first one is actually called JSymbol but the problem remains the same.
class JSymbol < ActiveRecord::Base
belongs_to :j_symbol_type
has_one :kanji, :dependent => :destroy
has_one :radical, :dependent => :destroy
has_one :vocabulary, :dependent => :destroy
attr_accessible :created_by_id, :updated_by_id, :symbol, :j_symbol_type_id, :level
attr_accessible :kanji_attributes, :radical_attributes, :vocabulary_attributes
accepts_nested_attributes_for :kanji, :radical, :vocabulary
end
And the Users model.
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable, :confirmable, :lockable, :timeoutable
attr_accessible :username, :email, :password, :password_confirmation, :remember_me
validates :username, :presence => true, :uniqueness => true
end
This is of course without the user-jsymbol relation since I am not sure what kind of relation to add in there.. It should be something like has_one :user
in JSymbol model and belongs_to :j_symbol
in User model except it needs to be done twice somehow.. There is also the matter of calling .build method in the action method for each Symbol.
Upvotes: 0
Views: 147
Reputation: 8642
After rmagnum2002 made me realize that I could use foreign_key parameter here, I started googling "rails multiple foreign key to same table", stumbled upon a bunch of outdated SO answers that didn't work and finally found this article which helped me write the code that works.
So, this is the relation that I put into my JSymbol model:
belongs_to :created_by, :class_name => User, :foreign_key => "created_by_id"
belongs_to :updated_by, :class_name => User, :foreign_key => "updated_by_id"
and this one is from Users model:
has_many :occurances_as_created_by, :class_name => JSymbol, :foreign_key => "created_by_id"
has_many :occurances_as_updated_by, :class_name => JSymbol, :foreign_key => "updated_by_id"
I didn't have to add anything in my action method, and this is what I put in the view:
<%= j_symbol.created_by.username %>
<%= j_symbol.updated_by.username %>
This is what happens in SQL if anyone is interested (which means it actually does it through separate select queries instead of joins so I might yet keep looking for a better solution):
JSymbol Load (0.3ms) SELECT "j_symbols".* FROM "j_symbols"
JSymbolType Load (0.3ms) SELECT "j_symbol_types".* FROM "j_symbol_types"
User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = 7 LIMIT 1
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."id" = 8 LIMIT 1
CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = 8 LIMIT 1
CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = 8 LIMIT 1
Rendered j_symbols/index.html.erb within layouts/j_symbols (7.8ms)
CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = 8 LIMIT 1
Upvotes: 0
Reputation: 11421
Something like this should work:
class Symbol < ActiveRecord::Base
has_many :creators, class_name: "User",
foreign_key: "created_by_id"
has_many :updaters, class_name: "User",
foreign_key: "updated_by_id"
belongs_to :creator, class_name: "User"
end
then use:
symbol | symbol.creator.name | symbol.updater.name
still, I am trying this on my app, so I am not sure 100% about it.
EDIT
class Symbol < ActiveRecord::Base
has_one :creator, :class_name => User, :foreign_key => 'created_by_id'
has_one :updater, :class_name => User, :foreign_key => 'updated_by_id'
end
Upvotes: 1