ActiveRecord::HasManyThroughAssociationNotFoundError in UserController#welcome - ruby-on-rails

I have a many to many relationship in rails. All database tables are named accordingly and appropriately. All model files are plural and use underscore to seperate words. All naming comventions are followed by ruby and rails standards. I'm using has many through in my models like this:
has_many :users, :through => :users_posts #Post model
has_many :posts, :through => :users_posts #User model
belongs_to :users #UsersSource model
belongs_to :posts #UsersSource model
What else could this error be from?
ActiveRecord::HasManyThroughAssociationNotFoundError in UsersController#welcome
Could not find the association :users_posts in model Post

You need to define the join model as a separate association when using has_many :through:
class Post < ActiveRecord::Base
has_many :user_posts
has_many :users, :through => :user_posts
end
class User < ActiveRecord::Base
has_many :user_posts
has_many :posts, :through => :user_posts
end
class UserPost < ActiveRecord::Base
belongs_to :user # foreign_key is user_id
belongs_to :post # foreign_key is post_id
end
This works best when you need to keep data that pertains to the join model itself, or if you want to perform validations on the join separate from the other two models.
If you just want a simple join table, it's easier to use the old HABTM syntax:
class User < ActiveRecord::Base
has_and_belongs_to_many :posts
end
class Post < ActiveRecord::Base
has_and_belongs_to_many :users
end

Related

Why is an association model for a many-to-many relationship only halfway pluralized?

I have a model User and a model Group, between the two I want to create a many-to-many association with a join-table, using through.
user.rb:
class User < ActiveRecord::Base
has_many :groups_user
has_many :groups, :through => :groups_user
end
group.rb:
class Group < ActiveRecord::Base
has_many :groups_user
has_many :users, :through => :groups_user
end
groups_user.rb
class GroupsUser < ActiveRecord::Base
belongs_to :user
belongs_to :group
end
I initially tried to do the same thing naming the joining model class GroupsUsers in groups_users.rb but I got an uninitialized constant error unless I used :class_name to specify the class name.
My question is: What is the logic behind pluralizing the first name, but not the second? The association is many-to-many so both models are on equal footing. In this case group comes first merely because of the lexical order. So why pluralize one and not the other? This makes no sense to me.
The more conventional naming approach would be:
#user.rb:
class User < ActiveRecord::Base
has_many :group_users
has_many :groups, :through => :group_users
end
#group.rb:
class Group < ActiveRecord::Base
has_many :group_users
has_many :users, :through => :group_users
end
#group_user.rb
class GroupUser < ActiveRecord::Base
belongs_to :user
belongs_to :group
end
Conventionally, the model has the singular form. So GroupsUser, not GroupsUsers. But, an instance of the join model has only one Group and one User, So, GroupUser, not GroupsUser.
If you look at the The has_many :through Association section of the Active Record Associations guide, for instance, you will see that the join model (Appointment) is singular. This is the pattern you want to follow.
If you decide to do things unconventionally, then rails needs you to help it - for instance by requiring that you specify class_name.

How do I specify a table with 2 foreign keys in rails?

If I have a legacy database where I the relationships between 2 entities are defined in a different table. How do I create that relationship in rails?
The basic relationship I want to present is:
---Admins:
First_name
Last_name
id
---Sites:
id
subject
---Admin_Sites
id
teacher_id
class_id
I know in rails I would just use belongs_to: and has_many: but if I have a (constantly updated) teach_class table, I need to somehow specify that THAT's where rails need to look for the relationship of who is related to which class. I am at a loss how I can specify this. Is it possible to somehow specify :foreign_key as "teach_class.teacher_id" in classes model?
In Teacher Model you would have
has_many :teach_classes
has_many :classes, :through => :teach_classes
see this blog for has_many :through relationship - http://ruby-on-rails-dipak-panchal.blogspot.in/2012/10/has-many-through-relationship.html
class Admin < ActiveRecord::Base
has_many :admin_sites
has_many :sites, :through => :admin_sites
end
class Site < ActiveRecord::Base
has_many :admin_sites
has_many :admins, :through => :admin_sites
end
class AdminSites < ActiveRecord::Base
belongs_to :admin
belongs_to :site
end

Rails Active Admin Many to Many relationships

I have the following models
class Owner < ActiveRecord::Base
has_many :business_owners
has_many :businesses, :through => :business_owner
end
class Business < Active Record::Base
has_many :business_owners
has_many :businesses, :through => :business_owner
end
class BusinessOwner < ActiveRecord::Base
belongs_to :owners
belongs_to :businesses
end
I have attempted to add the BusinessOwner model to the admin dashboard:
rails generate active_admin:resource BusinessOwner
which creates a file called business_owners in app/admin/
when I attempt to view the Business Owner I receive the following error:
uninitialized constant BusinessOwner::Owners
Extracted source (around line #1):
1: render renderer_for(:index)
Can someone tell me how to use active admin with many to many relationships?
Your relationships don't look right.
On the belongs_to relationships, Rails expects you to use the singular form
class BusinessOwner < ActiveRecord::Base
belongs_to :owner
belongs_to :business
end
Likewise, you need to correctly reference the :through
has_many :businesses, :through => :business_owners
(i.e. plural owners)
It's usually worth firing up the Rails console (OR WRITING TESTS, hehe) to test this stuff before you think about ActiveAdmin ;)
Correct in bussiness table do association like this:
class Business < Active Record::Base
has_many :business_owners
has_many :oweners, :through => :business_owner
end

Nested models with has_many in Rails

For example I have in my app model User, that has_many models Post. And Post has_many Attachment. So I can do this
user.posts
and this
post.attachment
But what if I want do smth like
user.attachments
Is there any build-in solution for this?
You would use a has_many through association. You should end up with something similar to the following structure:
class User < ActiveRecord::Base
has_many :posts
has_many :attachments, :through => :posts
end
class Post < ActiveRecord::Base
has_many :attachments
end
class Attachments < ActiveRecord::Base
belongs_to :posts
end
The relevant section from the above link:
The has_many :through association is also useful for setting up “shortcuts” through nested has_many associations...

In RoR, how do I create TWO one to one relationship between two tables?

In RoR3,
I have Users and Skills and each skill is created by a user. I wanted to record that, so I created a one to many relationship.
class User < ActiveRecord::Base
has_many :skills
end
class Skill < ActiveRecord::Base
belongs_to :user
end
However, each user also has many skills in the sense that, user "Bob" created skill "Kung Fu", user "Charlie" created skill "Karate" and user "Bob" both created and is able to do both "Kung Fu" and "Karate"
How should I represent this with ActiveRecord? Should I just create a new table "user_skills" which has_many :skills? and belong_to :user?
There are two different associations here. The first is a one-to-many association. An user can be the creator of any number of skills. The second one is a many-to-many association, an user can have many skills and a skill can have many users.
The first one is a simple belongs_to <-> has_many declaration. For the second one, you either need a has_and_belongs_to_many declaration in both models, and a related join table, or a dedicated join model, and a has_many :through declaration. Let's try the first one:
Method 1: HABTM
class User < ActiveRecord::Base
has_many :created_skills, :class_name => 'Skill', :inverse_of => :creator
has_and_belongs_to_many :skills
end
class Skill < ActiveRecord::Base
belongs_to :creator, :class_name => 'User', :inverse_of => :created_skills
has_and_belongs_to_many :users
end
This requires a join table called "skills_users" that has columns named user_id and skill_id
Method 2: Has many through (Join model)
The second one is similar, but adds a model that acts as the middleman. This has an added benefit that you can include additional columns in the join model, like for example a skill level.
class User < ActiveRecord::Base
has_many :created_skills, :class_name => 'Skill', :inverse_of => :creator
has_many :user_skills
has_many :skills, :through => :user_skills
end
class Skill < ActiveRecord::Base
belongs_to :creator, :class_name => 'User', :inverse_of => :created_skills
has_many :user_skills
has_many :users, :through => :user_skills
end
class UserSkill < ActiveRecord::Base
belongs_to :user
belongs_to :skill
end
Having those two models
class User < ActiveRecord::Base
has_and_belongs_to_many :skills
end
class Skill < ActiveRecord::Base
has_and_belongs_to_many :users
end
You would have to create an extra migration (without the model)
rails generate migration CreateSkillsUsersJoin
which will give you
class CreateSkillsUsersJoin < ActiveRecord::Migration
def self.up
create_table :skills_users, id => false do |t|
t.references "user"
t.references "skill"
end
add_index :skills_users,["user_id","skill_id"]
end
def self.down
drop_table :skills_users
end
end
The methods self.up and self.down you will have yo add them
You'd be well served using a gem like acts_as_taggable_on which you'd be able to simply setup and use in your User model, something like:
acts_as_taggable_on :skills
Honestly, they've figured all this stuff out, as it's not as simple as what you're trying to do, OR I should rephrase that and say, what you are trying to do is overtly 'complex' and this gem allows you to just keep on, keeping on after it's set up.
Read the Readme.

Resources