Rails inverse_of confusion - ruby-on-rails

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').

Related

Ruby on Rails how to distinguish multiple relationships between same models

So I have the following models
User, Course, Order, Line_item
User (seller) has_many :courses (as the instructor, uploading them)
On the other hand...
User (buyer): has_many :orders
Order: has many :line_items
line_item: belongs_to :course
So I want a list of all courses purchased by a buyer, can I at this point use #user.courses to do so? How can I distinguish between buyer.courses and seller.courses?
Any help is appreciated. Thanks!
You need to use self-referential association for this.
#cousre.rb
Class Course < ActiveRecord::Base
belongs_to :sellar, :class_name => 'User', :foreign_key => 'sellar_id'
end
#order.rb
Class Order < ActiveRecord::Base
belongs_to :buyer, :class_name => 'User', :foreign_key => 'buyer_id'
end

Mongoid could not determine the inverse foreign key to set

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.

Has_many through with multiple relationships between the entities

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

Association rules in rails

I have a User model, a Listing model and an Order model. A user can either place an order or publish a listing which others can place an order for. Thus, a User can be customer as well as supplier.
My Order model has listing_id, from_id and to_id.
My question is, how can I set up associations between these models ? I read the rails guide on associations but the example there were dealing with separate customer and supplier models.
class User < ActiveRecord::Base
has_many :listings, :foreign_key => :supplier_id, :inverse_of => :supplier
has_many :orders, :foreign_key => :customer_id, :inverse_of => :customer
end
class Listing < ActiveRecord::Base
belongs_to :supplier, :class_name => 'User'
belongs_to :order
end
class Order < ActiveRecord::Base
belongs_to :customer, :class_name => 'User'
has_many :listings
end

Rails has many and belongs to one

I have a User model which has many projects and a Project model which can have many users, but also belongs to a single user (ie the user who created this project). It must belong to a User. It also allows a list of users to be associated with it, think collaboration.
With this in mind, my models look like this:
class User < ActiveRecord::Base
has_many :assigned_projects
has_many :projects, :through => :assigned_projects
end
class Project < ActiveRecord::Base
belongs_to :user
has_many :assigned_projects
has_many :users, :through => :assigned_projects
end
class AssignedProject < ActiveRecord::Base
belongs_to :user
belongs_to :project
end
Now, when I want to create a new project through a User, this is how I would do it:
user = User.create(:name => 'injekt')
user.projects.create(:name => 'project one')
Now, I know that projects is provided through an AssignedProject join model, which is why project.user will return nil. What I'm struggling to get my head around is the best way to assign the project creator (which by the way doesn't need to be user, it could be creator or something else descriptive, as long as it is of type User).
The idea then is to create a method to return projects_created from a User which will select only projects created by this user. Where user.projects will of course return ALL projects a user is associated with.
Assuming this kind of association is fairly common, what's the best way to achieve what I want? Any direction is greatly appreciated.
Add a creator_id column to your projects table for the creator relationship, and then add the associations to the models:
class User < ActiveRecord::Base
has_many :assigned_projects
has_many :projects, :through => :assigned_projects
has_many :created_projects, :class_name => "Project", :foreign_key => :creator_id
end
class Project < ActiveRecord::Base
belongs_to :user
has_many :assigned_projects
has_many :users, :through => :assigned_projects
belongs_to :creator, :class_name => "User", :foreign_key => :creator_id
end
http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#method-i-has_many
I wanted to add little improvement to design. We don't actually need intermediate model because it does not contain any extra column other than reference_ids hence HABTM association is best suited over here.
class User < ActiveRecord::Base
has_and_belongs_to_many :projects, :join_table => :assigned_projects
has_many :created_projects, :class_name => "Project", :foreign_key => :creator_id
end
class Project < ActiveRecord::Base
has_and_belongs_to_many :users, :join_table => :assigned_projects
belongs_to :creator, :class_name => "User", :foreign_key => :creator_id
end

Resources