I have these model definitions:
class Property < ActiveRecord::Base
belongs_to :user
has_many :users_favourites_properties, class_name: 'UsersFavouritesProperties', dependent: :destroy, :foreign_key => :property_id
has_many :favourites, :class_name => "User", through: :users_favourites_properties
end
class User < ActiveRecord::Base
has_many :properties
has_many :users_favourites_properties, class_name: 'UsersFavouritesProperties', dependent: :destroy, :foreign_key => :user_id
has_many :favourites, class_name: "Property", through: :users_favourites_properties
end
class UsersFavouritesProperties < ActiveRecord::Base
self.table_name = "favourites"
belongs_to :favourites, class_name: 'User', :foreign_key => :user_id, :primary_key => :id
belongs_to :favourites, class_name: 'Property', :foreign_key => :property_id, :primary_key => :id, counter_cache: :users_count
end
When I execute:
current_user.favourites << property
The UsersFavouritesProperties object created has the same user_id and property_id because the user_id is beign setted with the property_id.
Do you know what is happening?
You seem to misunderstand what the association name is for.
Each association method call (like has_many) adds certain methods to a model that allow for easy lookup for associated objects.
The name of association means (in scope of a model) "what is it for me". A symbol you specify first is an association name, and it is used (among other things) as a name of a method that you will use to access that association.
By defining an association named favourites once, you've defined the methods for UsersFavouritesProperties. The second time you define an association with the same name, some of the first one is redefined and crazy things can happen.
So, following that "what is it for me" principle, you can figure that a User associated with a certain UsersFavouritesProperty is UsersFavouritesProperty's user, and the resulting association, that you have:
belongs_to :favourites, class_name: 'User', :foreign_key => :user_id, :primary_key => :id
should be more like simple:
belongs_to :user
The rest is not even needed, as it follows the Rails' convention: class name and foreign key can be derived from association name in standard ways (capitalize for class name, add _id for foreign key), primary key is default.
I strongly recommend you read the Rails Style Guide and let ActiveRecord guess the most you can provide.
These lines
belongs_to :favourites, ...
belongs_to :favourites, ...
Should be
belongs_to :user, ...
belongs_to :property, ...
You can't use two keys for belongs_to
Related
What does the ActiveRecord::Migration and ActiveRecord::Base look like for a class that references itself. I'm modeling an object that "forks" off an existing record and stores that relation in a :source field. That :source field will contain the primary_key :id of it's parent.
ActiveRecord doesn't include a "predefined" relation of this type, but you can define it yourself using the has_many and belongs_to helpers. You would need to add a foreign key, e.g. my_parent_id to the model (I'll call it Thing):
rails g migration AddMyParentIdToThings my_parent:references
Then you would need to define the relation specifying the foreign key and class names:
class Thing < ActiveRecord::Base
belongs_to :parent_thing, class_name: "Thing", foreign_key: :my_parent_id
has_many :child_things, class_name: "Thing", foreign_key: :my_parent_id
end
You can omit the :foreign_key option on the belongs_to (not the has_many) if the foreign key matches the relation name with an appended "_id" e.g.:
belongs_to :my_parent, class_name: "Thing"
When I had to do something like that I like to think of it as a model that links to itself.
In your migration file you just would add parent_id as as integer to that table/model
class Category < ActiveRecord::Base
belongs_to :parent, :class_name => "Category", :foreign_key => :parent_id
has_many :children, :class_name => "Category", :foreign_key => :parent_id
end
I have two models
class User
has_many :disputes
end
class Dispute
belongs_to :user
end
So Dispute has :user_id, but my problem is that a Dispute has 2 sides - the claimant and the indicted, both of which are users.
I tried to solve this problem by creating two columns: :claimant_id and :indicted_id, and passing arguments like #dispute.claimant_id = current_user.id, but after that I can't use a relationship tricks like #dispute.user.name or #user.disputes with my :claimant_id and :indicted_id.
Is there any way to set up two :user_id (like a claimant and an indicted) in one model and still maintain the relationships between Dispute and User models?
You can go the route of having :claimant_id and :indicted_id on your users table, but in your class def you need
class Dispute < ActiveRecord::Base
belongs_to :claimant, class_name: 'User', :foreign_key => :claimant_id
belongs_to :indicted, class_name: 'User', :foreign_key => :indicted_id
end
Reference: http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#method-i-belongs_to
I think this is a duplicate of Ruby on Rails Double Association
For your case use class_name as the second parameter to your belongs_to function and a hash with foreign_key and the id column name (as pointed out by #devkaoru), like so:
class Dispute < ActiveRecord::Base
belongs_to :claimant, class_name: 'User', :foreign_key => :claimant_id
belongs_to :indicted, class_name: 'User', :foreign_key => :indicted_id
end
I think that should do it up right.
Disclaimer: This is an untested solution
I'm building a simple ticket system in an application using MongoDB. At one point, I was able to create tickets, but now I am not. The User model is as follows:
class User
include Mongoid::Document
include Mongoid::Timestamps::Updated
has_many :initiated_tickets, :class_name => 'Ticket', :inverse_of => :initiator
has_many :assigned_tickets, :class_name => 'Ticket', :inverse_of => :assignee
The Ticket model is as follows:
class Ticket
include Mongoid::Document
include Mongoid::Timestamps::Updated
field :name
field :initiator_email
field :assignee_email
field :comment
belongs_to :alert
has_one :initiator, :class_name => 'User', :inverse_of => :initiated_tickets
belongs_to :assignee, :class_name => 'User', :inverse_of => :assigned_tickets
When I attempt to create a ticket, I get an error from Mongoid stating:
Mongoid::Errors::InverseNotFound:
Problem:
When adding a(n) User to Ticket#initiator, Mongoid could not determine the inverse foreign key to set. The attempted key was 'initiated_tickets_id'.
I'm not sure what's going wrong here. It looks like the inverse_of is set up correctly for both. Any idea why this isn't working, when it previously was? Thanks!
You only need inverse_of defined on the belongs_to side. Whereas, the has_many side should have the foreign_key defined. I have the exact same relation working as follows:
class User
has_many :initiated_tickets, foreign_key: "initiator_id", class_name: "Ticket"
has_many :assigned_tickets, foreign_key: "assignee_id", class_name: "Ticket"
class Ticket
field :initiator_id, :type => String
field :assignee_id, :type => String
belongs_to :initiator, inverse_of: "initiated_tickets" class_name: "User"
belongs_to :assignee, inverse_of: "assigned_tickets" class_name: "User"
EDIT
Rewrote my answer because I was mistaken originally.
I have these two models: Team and User.
Each user can have team and each team has many users. But I want to call team.users with team.members. I managed to do this with class_name, but I also need to have access to Team by User. In other words user.team should return me the team, in which the User is. Here is what I came up with...
My models are as follows:
class Team < ActiveRecord::Base
has_many :members, foreign_key: 'id', class_name: 'User', :inverse_of => :team
end
class User < ActiveRecord::Base
belongs_to :team, :inverse_of => :user
end
(I tried with :inverse_of => :members too, inside the User model.)
You got the :inverse_of right, at least when you use :inverse_of => :members. The problem here is the foreign key. foreign_key specifies the name of the key-column in the other table, so in your case in the user-table. If you specify just id, the id of the user would be used. Just leave it to the default by not specifying an foreign key, then its team_id.
class Team < ActiveRecord::Base
has_many :members, :class_name => 'User', :inverse_of => :team
end
class User < ActiveRecord::Base
belongs_to :team, :inverse_of => :members
end
And try to not mix hash-syntax from ruby 1.8 (:key => 'value') with the new syntax from ruby 1.9 (key: 'value').
I'm inheriting code which has:
class Graphic < ActiveRecord::Base
has_many :comments, :foreign_key => 'asset_id',
:conditions => 'asset_type_id = 5',
:order => 'created_at', :dependent => :destroy
class Comment < ActiveRecord::Base
belongs_to :graphic, :foreign_key => :asset_id
It seems to me like the has_many should not have the foreign_key (it's referenced in the belongs_to ok I believe) but I am not sure, do you know?
i.e. should it be
class Graphic < ActiveRecord::Base
has_many :comments,
:conditions => 'asset_type_id = 5',
:order => 'created_at', :dependent => :destroy
class Comment < ActiveRecord::Base
belongs_to :graphic, :foreign_key => :asset_id
I think you are trying to do something that is already baked in Rails. You should use Polymorphic Associations here.
class Comment
belongs_to :asset, :polymorphic => true
end
class Graphic
has_many :comments, :as => :assets
end
This way, you need to declare foreign_key on neither side.
In a has_many statement for rails, :foreign_key is indeed an option which has this description in the ActiveRecord documentation:
Specify the foreign key used for the association. By default this is guessed to be the name of this class in lower-case and “_id” suffixed. So a Person class that makes a has_many association will use “person_id” as the default :foreign_key.
So in your case, it looks as though you do need the foreign_key attribute on your has_many statement, since it differs from the name of the class.
However, you shouldn't need the foreign_key declaration in your belongs_to statement. Here is the description for the :foreign_key option for a belongs_to relationship in the ActiveRecord documentation:
Specify the foreign key used for the association. By default this is guessed to be the name of the association with an “_id” suffix. So a class that defines a belongs_to :person association will use “person_id” as the default :foreign_key. Similarly, belongs_to :favorite_person, :class_name => "Person" will use a foreign key of “favorite_person_id”.
I'm assuming that what you really meant to write for your Comment class is this:
class Comment < ActiveRecord::Base
belongs_to :graphic, :foreign_key => :graphic_id
In this case you could simplify the belongs_to statement to simply this:
belongs_to :graphic