Rails 3. has_many as another class - ruby-on-rails

So I have two models: User and ScheduledSession
The users have roles. One of the roles is "instructor".
ScheduledSession
belongs_to :instructor, :class_name => 'User', :foreign_key => 'instructor_id'
User
has_many :scheduled_sessions
GOOD! So I can do this...
s = ScheduledSession.first
s.instructor
BAD! But I can't do this...
u = User.first
u.scheduled_sessions
I get this error...
SQLite3::SQLException: no such column: scheduled_sessions.user_id: SELECT "scheduled_sessions".* FROM "scheduled_sessions" WHERE "scheduled_sessions"."user_id" = 1
ActiveRecord::StatementInvalid: SQLite3::SQLException: no such column: scheduled_sessions.user_id: SELECT "scheduled_sessions".* FROM "scheduled_sessions" WHERE "scheduled_sessions"."user_id" = 1
How can I setup the relationship the other way around so I can see which scheduled sessions belongs to that instructor (user)?

You just need to set the foreign key in the User has_many relationship as well.
has_many :scheduled_sessions, :foreign_key => 'instructor_id'

Related

Problems with belongs_to condition in model

I'm making personal money management app. There I have 2 models: Account and Transaction.
Transaction has belongs_to :account and Account has has_many :transactions.
When I had account_id column in db (postgres) everything worked fine. But I have to rename account_id to from_account_id and add another column to_account_id. So that I can add a spending from Account and income to Account. Also it's necessary for transfers between accounts (where from_account_id and to_account_id both will have some values).
So, I've renamed fields :account_id in my views to :from_account_id and add :to_account_id field. But, when I rename account_id to from_account_id in db, I've got this error.
ActiveRecord::StatementInvalid in PagesController#index
PG::Error: ERROR: column transactions.account_id does not exist
LINE 1: ...s".* FROM "transactions" INNER JOIN "accounts" ON "transacti...
^
: SELECT "transactions".* FROM "transactions" INNER JOIN "accounts" ON
"transactions"."account_id" = "accounts"."id" WHERE "accounts"."user_id" = 17 ORDER BY
transactions.date DESC
My Pages#index controller is:
class PagesController < ApplicationController
def index
if user_signed_in?
#accounts = current_user.accounts.all
#transaction = current_user.transactions.build
#transactions = current_user.transactions.all
#categories = current_user.categories.all
end
end
end
I think Rails is trying to find account_id column in transactions table, because Transaction belongs_to :account. But I need both columns for :account to and from, as you see. So, maybe I need to change this belongs_to condition in Transaction model, but I don't know how.
Thanks for any ideas!
You have to define two belong_to relations in your Transaction class, one for each column in your table transactions:
class Transaction < ActiveRecord::Base
belongs_to :from_account, :class_name => 'Account', :foreign_key => 'from_account_id'
belongs_to :to_account, :class_name => 'Account', :foreign_key => 'to_account_id'
# ...
end
See options in Rails Relation Guide
Yo have to rename the has_many relation in Account model. Something like below will work:
has_many :transactions, :foreign_key => "from_account_id"

Rails - association with another table

I have a users table(and a user model). In my scenario, a user can have multiple identities. I.e. user michael1 (id = 1) can be connected to michael2 (id = 2) and michael3 (id = 3).
I created a table to store these connections. I called it user_relations and it has: id, user_id, related_user_id columns. In the previous example I'll have:
user_id | related_user_id
1 | 2
1 | 3
In users model I defined: has_many :user_relations, and in user_relation I defined: belongs_to :users.
Now, I want that when I have a user object I would be able to get:
current_user.user_relations - and get all users objects that are connected according to the table. In previous example, if I have current_user as user with id 1, I would like to get users with id 2 and 3.
How can I achieve that?
BTW - I have an id because I saw that without it, I am not able to use destroy_all. If anyone has an insight regarding this also, I am open to hear.
I think this should work. If I missed something you can look here for details:
class User < ActiveRecord::Base
has_many :user_relations
has_many :related_users, :through=> :user_relations
end
class UserRelations< ActiveRecord::Base
belongs_to :user, :class_name => "User", :foreign_key => "user_id"
belongs_to :related_user, :class_name => "User", :foreign_key => "related_user_id"
end

Eager Loading in a Rails 3 app

I am trying to reduce the number of database queries in my Rails 3 app.
User model:
has_many :agreements
Agreement model:
belongs_to :user
The agreements table has two user id fields... payer_id and payee_id. Is it possible to make something like the following work:
user_payer_agreements = current_user.agreements
user_payee_agreements = current_user.agreements
I could use user_id for one side of the transaction but I need to get both sides. Is it possible to specify payer_id or payee_id instead of user_id in the process of creating an association? If not, do i need use a join or a sql statement. Any help is appreciated.
You can do this:
has_many :payer_agreements, :class_name => 'Agreement', :foreign_key => :payer_id
has_many :payee_agreements, :class_name => 'Agreement', :foreign_key => :payee_id
With this you can do:
current_user.payer_agreements
current_user.payee_agreements
Is this what you are looking for?

Rails: One-to-many association

I'm using Rails 3 and I've got a one to many association I'm trying to define: A user can have many subject families assigned to him/her, but a subject family can only be assigned to one user.
Here's what I have defined:
class User
has_many :subject_families
class SubjectFamily
belongs_to :assignee, :class_name => "User", :foreign_key => 'assigned_to'
I added a migration that does this:
change_table(:subject_families) do |t|
t.integer :assigned_to
end
I'm getting an exception when I try to do:
u = User.first
s = u.subject_families
Here's the exception:
Invalid column name 'user_id'.: SELECT [subject_families].* FROM [subject_families] WHERE ([subject_families].user_id = 1)
I was expecting this to be using subject_families.assigned_to rather than user_id but lo and behold I was disappointed in this expectation. Can anyone see what I might have missed here? I've googled this a lot and from what I can see this SHOULD work.
I believe you also need to specify the :foreign_key option on the has_many association declaration in your User model.
class User
has_many :subject_families, :foreign_key => 'assigned_to'
You need to specify :foreign_key => 'assigned_to' in the has_many relationship on User as well.

has_many through help, what am I doing wrong?

My models are like this:
User
has_and_belongs_to_many :Roles
Role
has_and_belongs_to_many :Users
tables:
roles_users
user_id
role_id
roleGroups
id
role_id
some_column
Now I want to create another association on the User model, that will be a collection of all roleGroups the user belongs to.
i.e. if the user is in roles with id's 1 and 2, then fetch all RoleGroups where role_id = 1 and 2.
I think I need to use a through because it is based on the user's Role association right?
I tried:
User
has_many :RoleGroups, :through => :Roles
Role
has_many :RoleGroups, :through => :User
But I get an error saying:
ActiveRecord::HasManyThroughSourceAssociationMacroError: Invalid source reflection macro :has_many :through for has_many :RoleGroups, :through => :Roles. Use :source to specify the source reflection.
Update
Ok my models look like this now:
User
habtm :Roles
has_many :RoleGroups, :through => :Roles
Role
habtm :Users
has_many :RoleGroups
RoleGroup
belongs_to :Role
mysql tables:
roles_users
user_id
role_id
role_groups
id
role_id
col3
col4
..
If I do:
u = User.find(1)
u.Roles (works fine)
u.RoleGroups #see error
Error message:
ActiveRecord::StatementInvalid: Mysql2::Error: Unknown column 'roles.user_id' in 'where clause': SELECT `role_groups`.* FROM `role_groups` INNER JOIN `roles` ON `role_groups`.role_id = `roles`.id WHERE ((`roles`.user_id = 1))
You're looking for the has_and_belongs_to_many association.
You can't do this the way you're thinking. I'm not sure why you're capitalizing your associations, but there are a few other things wrong, too.
First, RoleGroups hangs off of Role (via has_many, but more on that in a sec), which means you don't have a direct connection between User and RoleGroup.
Second, it appears from your updated explanation that each RoleGroup can have more than one Role, which is normal, but in your code Role has_many :role_groups, which means each role can have more than one role group. This is counterintuitive naming, but perhaps intentional. I'm going to assume that your role groups contain multiple roles rather than the other way around.
Third, you can't use a HABTM as a :through model. HABTM only uses a table in the database, not a Rails model, so the information in your roles_users table can't be used directly; has_many :foos :through => :bars requires an actual Bar model.
# Models
User
habtm :roles
Role
habtm :users
belongs_to :role_group # add role.role_group_id attribute
RoleGroup
has_many :roles # remove role_groups.role_id attribute
# Console
u = User.find(1) # get user
r = u.roles # get user roles
u.roles.collect { |role| role.role_group.name }
# ["Administrative","Editorial","User"]

Resources