Pluralized many-to-many but still uninitialized constant - ruby-on-rails

As per the below I think this setup is fine:
class Location < ActiveRecord::Base
has_many :traders
has_many :servicelocations
has_many :services, through: :servicelocations
end
class Service < ActiveRecord::Base
has_many :servicelocations
has_many :locations, through: :servicelocations
end
class ServiceLocation < ActiveRecord::Base
belongs_to :location
belongs_to :service
end
class Trader < ActiveRecord::Base
belongs_to :location
end
The problem is I am still getting an uninitialized constant error.
I have noticed that as I created the model ServiceLocation, funky rails magic created service_location.rb but I am unsure if a) this is the problem and b) how to fix it if it is.

I believe your error came from this
class Service < ActiveRecord::Base
has_many :servicelocations
has_many :locations, through: :servicelocations
end
These should be like this
class Service < ActiveRecord::Base
has_many :service_locations
has_many :locations, through: :service_locations # notice the underscore
end
Your model Class name is ServiceLocation and the rails convention name for this is service_location not servicelocation
And here also,you have to change
class Location < ActiveRecord::Base
has_many :traders
has_many :service_locations
has_many :services, through: :service_locations
end

I guess ruby understand servicelocations like one word, so you need to change model to Servicelocation or change association to service_locations. Second method i guess is better, it would be like:
class Location < ActiveRecord::Base
has_many :traders
has_many :service_locations
has_many :services, through: :service_locations
end
class Service < ActiveRecord::Base
has_many :service_locations
has_many :locations, through: :service_locations
end

Related

How to setup model associations in Rails

I'm trying to create associations for three models in my Rails application. In the application a User can access courses which have videos. How would I model this?
This is what I currently have:
class User < ApplicationRecord
has_many :courses
has_many :videos, through: :courses
end
class Course < ApplicationRecord
belongs_to :user
has_many :videos
end
class Video < ApplicationRecord
belongs_to :course
belongs_to :user
end
Is this the correct way to model these associations for what I want the application to be able to achieve?
Normally, this would look something like:
class UserCourse < ApplicationRecord
belongs_to :user
belongs_to :course
end
class User < ApplicationRecord
has_many :user_courses
has_many :courses, through: :user_courses
has_many :videos, through: :courses
end
class Course < ApplicationRecord
has_many :user_courses
has_many :users, through: :user_courses
has_many :videos
end
class Video < ApplicationRecord
belongs_to :course
has_many :users, through: :course
end
That should let you do:
#user.courses
#user.videos
#course.users
#course.videos
#video.course
#video.users
(Assuming, of course, you've instantiated each of the above variables and you have associated records.)

ActiveRecord::HasManyThroughOrderError: Cannot have a has_many :through association

In my rails app I'm trying to create a system that will reward users with badges for various achievements
created a table 'user_badges'
migration:
class CreateUserBadges < ActiveRecord::Migration[5.1]
def change
create_table :user_badges do |t|
t.references :user, foreign_key: true
t.references :badge, foreign_key: true
t.timestamps
end
end
end
model UserBadge:
class UserBadge < ApplicationRecord
belongs_to :user
belongs_to :badge
end
модель Badge:
class Badge < ApplicationRecord
has_many :users, through: :user_badges
has_many :user_badges
end
model User:
class User < ApplicationRecord
...
has_many :badges, through: :user_badges
has_many :user_badges
...
end
when I try to add a badge to the user:
b = Badge.create(title: 'first')
User.last.badges << b
I get this error:
ActiveRecord::HasManyThroughOrderError: Cannot have a has_many
:through association 'User#badges' which goes through
'User#user_badges' before the through association is defined.
also when I simply call:
User.last.badges
same error:
ActiveRecord::HasManyThroughOrderError: Cannot have a has_many
:through association 'User#badges' which goes through
'User#user_badges' before the through association is defined.
Define has_many association first then add through: association
class UserBadge < ApplicationRecord
belongs_to :user
belongs_to :badge
end
class Badge < ApplicationRecord
has_many :user_badges # has_many association comes first
has_many :users, through: :user_badges #through association comes after
end
class User < ApplicationRecord
...
has_many :user_badges
has_many :badges, through: :user_badges
...
end
Note, in case you mistakenly wrote first has_many 2 times, then it can reproduce this error too. E.g.
class User < ApplicationRecord
...
has_many :user_badges
has_many :badges, through: :user_badges
...
has_many :user_badges
end
# => Leads to the error of ActiveRecord::HasManyThroughOrderError: Cannot have a has_many :through association 'User#badges' which goes through 'User#user_badges' before the through association is defined.
Active Record should alert has_many being used two times IMHO...

has_many of the same table through several others

What am trying to do is:
i have a User model and i have a Task model
Task has 2 types of users Owners and Supervisors all of them are users !
so what i have so far is:
Task Model
class Task < ActiveRecord::Base
has_many :task_owners, dependent: :destroy
has_many :task_supervisors, dependent: :destroy
has_many :users, through: :task_owners
has_many :users, through: :task_supervisors
end
TaskSupervisor Model
class TaskSupervisor < ActiveRecord::Base
belongs_to :task
belongs_to :user
end
TaskOwner Model
class TaskOwner < ActiveRecord::Base
belongs_to :task
belongs_to :user
end
and finally the User Model
class User < ActiveRecord::Base
has_many :task_owners
has_many :task_supervisors
has_many :tasks, through: :task_owners
has_many :tasks, through: :task_supervisors
end
now as you can imagine ... my problem is when i get a task and retrieve the users i only get one of my associations ... what i need is a way to change the getters name or identify them some how basically to be able to say something like
task.owners
task.supervisors
class Task < ActiveRecord::Base
has_many :task_owners, dependent: :destroy
has_many :task_supervisors, dependent: :destroy
has_many :owners, through: :task_owners, source: :users
has_many :supervisors, through: :task_supervisors, source: :users
end
You should be able to do this.
Then you should get your task.owners and task.supervisors
Edit:
You will need to change your user model to
class User < ActiveRecord::Base
has_many :task_owners
has_many :task_supervisors
has_many :owned_tasks, through: :task_owners, source: :tasks
has_many :supervised_tasks, through: :task_supervisors, source: :tasks
end

Modeling "Likes" in rails HABTM vs HM/BT

What would be the best method to model "likes" in rails for my app. I could either to the following:
class User < ActiveRecord::Base
has_many :things
has_many :likes
has_many :liked_things, through: :likes, source: :thing
end
class Like < ActiveRecord::Base
belongs_to :user
belongs_to :thing
end
class Thing < ActiveRecord::Base
belongs_to :user
has_many :likes
has_many :liking_users, through: :likes, source: :user
end
Or
class User < ActiveRecord::Base
has_many :things
has_and_belongs_to_many :things
end
class Thing < ActiveRecord::Base
belongs_to :user
has_and_belongs_to_many :users
end
What approach would be best and why? I plan to have an activity feed in my app as well, if that helps determine the best approach.
The answer to this question depends on whether or not Like will ever have any attributes or methods.
If its only purpose of existence is to be the HABTM relationship between Users and Things, then using the has_and_belongs_to_many relationship would suffice. In your example, having has_many and belongs_to is redundant. All you would need in this case is:
class User < ActiveRecord::Base
has_and_belongs_to_many :things
end
class Thing < ActiveRecord::Base
has_and_belongs_to_many :users
end
On the other hand, if you anticipate that a Like will have an attribute (e.g. maybe someone will really like something, or love it, etc.) then you can do
class User < ActiveRecord::Base
has_many :likes
has_many :liked_things, through: :likes, source: :thing
end
class Like < ActiveRecord::Base
belongs_to :user
belongs_to :thing
end
class Thing < ActiveRecord::Base
has_many :likes
has_many :liking_users, through: :likes, source: :user
end
Note that I removed has_many :things and belongs_to :user as they are redundant.

twitter model associations in rails

I am trying to build a twitter like data model in rails. This is what I have come up with.
class User < ActiveRecord::Base
has_many :microposts, :dependent => :destroy
end
class Micropost < ActiveRecord::Base
belongs_to :user
has_many :mentions
has_many :hashtags
end
class Mention< ActiveRecord::Base
belongs_to :micropost
end
class Hashtag < ActiveRecord::Base
belongs_to :micropost
end
Should I be using a has_many through association somewhere or is this accurate?
Edit: The final twitter MVC model.
class User < ActiveRecord::Base
has_many :microposts, :dependent => :destroy
userID
end
class Micropost < ActiveRecord::Base
belongs_to :user
has_many :link2mentions, :dependent => :destroy
has_many :mentions, through: :link2mentions
has_many :link2hashtags, :dependent => :destroy
has_many :hashtags, through: :link2hashtags
UserID
micropostID
content
end
class Link2mention < ActiveRecord::Base
belongs_to :micropost
belongs_to :mention
linkID
micropostID
mentionID
end
class Mention < ActiveRecord::Base
has_many :link2mentions, :dependent => :destroy
has_many :microposts, through: :link2mentions
mentionID
userID
end
Edit 2: A concise and accurate explanation
http://railscasts.com/episodes/382-tagging?view=asciicast
If two microposts use the same hashtag, you probably don't want to create two database records for that hashtag. In this case you would use has_many through:
class Hashtagging < ActiveRecord::Base
belongs_to :micropost
belongs_to :hashtag
end
class Hashtag < ActiveRecord::Base
has_many :hashtaggings
has_many :microposts, through: :hashtaggings
end
class Micropost < ActiveRecord::Base
...
has_many :hashtaggings
has_many :hashtags, through: :hashtaggings
end
When you create the Hashtagging migration, make sure it has the micropost_id and hashtag_id columns.

Resources