Rails model foreign key not working when specifying explicitly - ruby-on-rails

I have a User model and a Message model. My message table has the columns created_for, and created_by and these are both foreign keys to the User table.
I'm currently getting this error message:
undefined methodcreated_for_id' for #`
How can I get this to work without having to change my columns to created_for_id and created_by_id?
class User < ActiveRecord::Base
has_one :message
end
class Message < ActiveRecord::Base
#belongs_to :user
belongs_to :created_by, :class_name => "User" # Basically tell rails that created_by is a FK to the users table
belongs_to :created_for, :class_name => "User" # Basically tell rails that created_for is a FK to the users table
attr_accessible :created_by, :created_for, :message
end

You can specify the foreign key for the belongs_to via:
belongs_to :created_for, class_name: 'User', foreign_key: :created_for
I suspect you are going to run into an issue having the relation name and foreign key attribute sharing a name. Here is the belongs_to documentation, scroll down to the "Options"

Related

model relation going both ways with foreign key

I have two models reservations and reviews I can go reservation.review and get a correct output in cases. However, when i go review.reservation im not getting the same respect i get the relation error StatementInvalid.
Reviews model:
belongs_to :reservation, :foreign_key => :reservation_id, class_name: 'Reservation'
belongs_to :reviser
has_one :reviser
has_one :reservation
belongs_to :user
Reservation model:
has_one :review, :dependent => :destroy
A few things to note about your reviews model. You have this line:
belongs_to :reservation, :foreign_key => :reservation_id, class_name: 'Reservation'
but since you're naming the foreign key reservation_id, which is what rails names the foreign key by default, you can simply get rid of that part and say:
belongs_to :reservation
Secondly, I'm not totally sure why you have has_one :reservation since you already have belongs_to :reservation. I would probably delete the has_one :reservation line unless you're absolutely sure it should be there.
So your new reviews model would look like this:
belongs_to :reservation
belongs_to :reviser
has_one :reviser
belongs_to :user
I would double check in your schema.rb file to ensure that you have the field reservation_id in your reviews table. That field must be present for the association to work properly.

Understanding use of foreign_key and class_name in association

I am new to rails and this is a very basic question. I am trying to understand the need of foreign key and class_name.
has_many :task, foreign_key: "created_by"
has_many :memberships, class_name: "TaskMembership"
Can anyone explain the need of foreign_key & class_name.
Here is the answer of my question
Suppose you have a User model and Post model.And you have to set an association like User has many post
User Model
has_many :posts
Post Model
belongs_to :user
Now suppose your user is some author so we have to set some meaningful name so instead of user we will use author but have to specify which class it is referring
Post Model
belongs_to :author, class_name: 'User'
Now problem will occur because rails will look for author_id column in posts table .So here foreign key will come into picture.We will have to find user_id
Post Model
belongs_to :author, class_name: 'User', foreign_key: 'user_id'
See more better explanation association
has_many association is used for for one-to-many type relationships in rails. For instance, if you have a model User which can has many profiles, your User to Profile association will be has many.
class User < ActiveRecord::Base
has_many :profiles
end
class Profile < ActiveRecord::Base
belongs_to :user
end
If you have a foreign key different than user_id in profiles table, you explicitly specify foreign_key. Same is the case with class name. If your association name is different than actual model name, you explicitly specify class name after association (as you did for memberships).
Hope it helps.
in your model
class First < ActiveRecord::Base
has_many :seconds
end
class Second < ActiveRecord::Base
belongs_to :first
end
and in your second class table,create first_id column

rails has_many: through not working when using the word "connection"

I'm able to successfully create a through table using the naming convention of friends and friend. However I'd like to use connections instead of friends.
Active record throws the following error when I try to use connections: PG::UndefinedColumn: ERROR: column medical_relationships.connection_id does not exist
class User < AR::Base
has_many: :medical_relationships
has_many: :friends, through: :medical_relationships
# I'd like to use
# has_many: :connections, through: :medical_relationships
class MedicalRelationship < AR::Base
belongs_to :user
belongs_to :friend, :class_name => "User"
# belongs_to :connection, :class_name => "User"
this seems to be a singular and plural naming convention issue in rails but I'm not sure.
That id does not exist on the medical_relationships table. You can either add :foreign_key => :user_id (assuming that is your user table's primary key) or change the name of the column in the table. I would advise against the second.

How do I validate uniqueness of join table with extra column in Ruby on Rails

I have a has many through relationship in a model that is self referencing. In the join table I also have an extra column that defines the source of the relationship. When adding a new object to that relationship I'd like to avoid duplicates in the join table based on the user_id, friend_id, and source_id
User Model
class User < ActiveRecord::Base
has_many :friendships
has_many :friends, :class_name => "User", :through => :friendships
end
Join Model
class Friendship < ActiveRecord::Base
attr_accessible :friend_id, :user_id, :source_id, :alert, :hide
# Relationships
belongs_to :user
belongs_to :friend, :class_name => "User"
has_one :source
end
I understand that I can do this
unless user.friends.include?(newFriend)
user.friendships.build(:friend_id => friendUser.id, :source_id => source.id)
end
But that seems like it will check to see if the new user exists in the current user's friends. I need to check on the join model level and make sure that the connection doesn't exist with the given source id.
I know there are several ways to accomplish this, but I'm pretty new to ruby on rails and am looking for the "rails way" to do it.
You can validate based on multiple columns in your intermediate table like this:
validates_uniqueness_of :user_id, :scope => [:friend_id, :source_id]

has_one and has_many in same model. How does rails track them?

I a little confused about how this work even if it works properly. I have a model that has two association to the same other model.
Company has an owner and company has many employees of the class users.
here is my company model:
class Company < ActiveRecord::Base
validates_presence_of :name
has_many :employee, :class_name => 'User'
has_one :owner, :class_name => 'User'
accepts_nested_attributes_for :owner, :allow_destroy => true
end
here is my user model:
class User < ActiveRecord::Base
include Clearance::User
attr_accessible :lastname, :firstname #other attr are whitelisted in clearance gem
validates_presence_of :lastname, :firstname
belongs_to :company
end
Now assuming I have 3 employee of this company including the owner. When I first create the company I set the owner to the employee with id 1 and the two others (2,3) are added to the employee list by setting their company_id (user.company=company). All three have their company_id set to the company id which we can assume is 1
when I ask for company.owner, I get the right user and when I do company.employee, I get all three.
If I change the owner to user 2, it removes user 1 from the employees automatically by setting it's company_id to nil. This is fine and if I add him back as a simple employee all is still good.
How the heck does rails know which is which? What I mean is how does it know that an employee is owner and not just an employee? Nothing in the schema defines this.
I have a feeling I should reverse the owner association and make company belong_to a user.
As you have it now, there's nothing to distinguish owners from employees. Which means you're going to run into problems once you start removing people or try to change ownership.
As François points out, you're just lucking out in that the owner is the user that belongs to company with the lowest ID.
To fix the problem I would have my models relate in the following maner.
class Company < ActiveRecord::Base
belongs_to :owner, :class_name => "user"
has_many :employees, :class_name => "user"
validates_presence_of :name
accepts_nested_attributes_for :owner, :allow_destroy => true
end
class User < ActiveRecord::Base
include Clearance::User
attr_accessible :lastname, :firstname #other attr are whitelisted in clearance gem
validates_presence_of :lastname, :firstname
belongs_to :company
has_one :company, :foreign_key => :owner_id
end
You'll have to add another column called owner_id to the Companies table, but this more clearly defines your relationships. And will avoid any troubles associated with changing the owner. Take note that there might be a cyclical dependency if you go this route and have your database set so that both users.company_id and companies.owner_id cannot be null.
I'm not quite sure how well accepts_nested_attributes_for will play with a belongs_to relationship.
has_one is syntactic sugar for:
has_many :whatevers, :limit => 1
has one adds the :limit => 1 bit, thereby ensuring only 1 record is ever returned. In your has one declaration, make sure you have an :order clause, to return the right record in all circumstances. In this instance, I'd put a flag on the Employee to signify who is the owner, and sort by this column to get the right record 1st.
Your question about how come Rails knows this is because most databases will return records in their primary key order. So, the 1st added employee has ID 1, thereby will be returned 1st.
You could have a model called ownership -
ownership belongs_to company
ownership belongs_to user
user has_many ownerships
company has_one ownership

Resources