Rails: accessing associated models with several degrees of separation - ruby-on-rails

I am a beginner in rails, and I have a question about accessing one model from another model that is associated with several degrees of separation.
Let's say I have these models:
Account has_many Spies
Spy has many SpyRelationships and belongs to Account
SpyRelationship belongs to Listing and belongs to Spy
How would I set up the associations so that I could simply pull all the listings associated with a given Account (via its spies and spyrelationships)? What line of code would allow me to do so, after those associations are setup properly?

I'm guessing you want to access a listing through a spy?
class Account < ActiveRecord::Base
has_many :spies
has_many :listings, through: :spies
end
class Spy < ActiveRecord::Base
belongs_to :account
has_many :spy_relationships
has_many :listings, through: :spy_relationships
end
class SpyRelationship < ActiveRecord::Base
belongs_to :listing
belongs_to :spy
end
class Listing < ActiveRecord::Base
has_many :spy_relationships
end

Related

How to reference a field in the join model of a has_many though Rails 5 relationship

I am working on an app where users have many quizzes and quizzes can have many users. I have set the relationships:
class User < ApplicationRecord
has_many :studies
has_many :quizzes, through: :studies
end
class Quiz < ApplicationRecord
has_many :studies
has_many :users, through: :studies
end
class Study < ApplicationRecord
belongs_to :user
belongs_to :quiz
end
I have a field in the Study table to store the score that the user made on the quiz, but I am unable to access the field. I have tried #quiz.studies.score and #quiz.study.score but Rails give me an undefined method. How to I access the field in a join model of a has_many though relationship?
#quiz.studies return the collection of studies. So you have to use first, last, each to get the score of the specific studies.
Try this:
#quiz.studies.first.score

Multiple has_many through relationships Rails

I'm still learning how to use has_many and has_many through relationships effectly. I am currently building a system where I would like users to be able to access certain maps that they are added to.
The map model is what I need the user to be able to access if they are apart of a certain group.
class Map < ApplicationRecord
has_many :rows
has_many :mapgroups
has_many :groups, through: :mapgroups
end
Since a user can belong to many groups I have a has_many through relationship
class Usergroup < ApplicationRecord
belongs_to :user
belongs_to :group
end
class User < ApplicationRecord
has_many :usergroups
has_many :groups, through: :usergroups
end
class Group < ApplicationRecord
has_many :usergroups
has_many :users, through: :usergroups
has_many :mapgroups
has_many :maps, through: :mapgroups
end
I thought about making a mapgroup model to take care of this but, so far, I am not so sure this is going to work.
class Mapgroup < ApplicationRecord
belongs_to :map
belongs_to :group
end
I am looking for a method to check to see what groups the user is apart of and then, based on those groups, give the user access to the corresponding maps. Am I on the right track with the relationships? How could I do this?
If you want to use MapGroup model only for keeping users an map connected (ModelGroup has only foreign keys on Group and Map) it's not the best approach. In this case it's better to opt for has_and_belongs_to_many assosiation. It will let you to assosiate Groups and Maps without creating useless model.
A has_and_belongs_to_many association creates a direct many-to-many connection with another model, with no intervening model.
class Group < ApplicationRecord
...
has_and_belongs_to_many :maps
end
class Map < ApplicationRecord
...
has_and_belongs_to_many :groups
end

What is the correct naming method for Rails models that represent a join table?

I have two classes (organisation.rb and user.rb) which are linked through a join table via ActiveRecord with a many to many relationship. A user can belong to many organisations, and an organisation can have many users.
Initially, I represented this relationship in this manner and this worked fine:
class Organisation < ActiveRecord::Base
has_many :members, through: :memberships, source: :user
has_many :memberships
end
class User < ActiveRecord::Base
has_many :organisation_members, through: :memberships, source: :organisation
has_many :memberships
end
class Membership < ActiveRecord::Base
belongs_to :user
belongs_to :organisation
end
I asked a friend to review my pull request and he suggested that the Rails convention is to name the join table with a lexical ordered list of the tables to be joined. I searched and confirmed this:
Rails naming convention for join table
As such, I reverted my migrations and started anew, with the new relationships:
class Organisation < ActiveRecord::Base
has_many :members, through: :organisations_users, source: :user
has_many :organisations_users
end
class User < ActiveRecord::Base
has_many :organisation_memberships, through: :organisations_users, source: :organisation
has_many :organisations_user
end
class OrganisationsUser < ActiveRecord::Base
belongs_to :user
belongs_to :organisation
end
Having made these changes, a number of my tests failed due to not recognising the model 'organisation_user.rb'. I then tried 'organisations_users.rb', and also no luck. This was due to my ignorance of rails' pluralisation, and therefore naming the join table model correctly resulted in all tests passing. As described above, the correct naming is:
class OrganisationsUser
This results in a rather strange model name of a pluralised organisation followed by a singular user.
I understand that this is technically correct. The model name should singular, however it isn't particularly easy to understand when compared with the 'memberships' join table.
What is the correct way to handle this - should I revert back to memberships, find a way to override Rails' default pluralisation, or continue with the awkwardly named status quo?

How to model table with items which have multiple subcategories?

I need some advice. I am pretty new in modeling database so I was wondering what would be the most convenient way to model database which would make my life easier. I have one Car item which can have multiple descriptive subcategories, like TireCategory, GlassCategory, EngineCategory...
I was thinking about doing something like this:
class Car < ActiveRecord::Base
belongs_to :tire_category
belongs_to :glass_category
belongs_to :engine_category
#Car would have three additional columns: tire_category_id, glass_category_id, engine_category_id
end
class TireCategory < ActiveRecord::Base
has_many :cars
end
class GlassCategory < ActiveRecord::Base
has_many :cars
end
class EngineCategory < ActiveRecord::Base
has_many :cars
end
Is this recommended way to do it or some other relation would be more suitable? Thank you!
You can store cars (with uniq data like model name and sku) in one table, properties (like engines, glasses) in another, and one more table for relation between cars and properties.
class Car < ActiveRecord::Base
has_many :car_properties, dependent: :destroy
has_many :properties, through: :car_properties
end
class Property < ActiveRecord::Base
has_many :car_properties, dependent: :destroy
has_many :cars, through: :car_properties
end
class CarProperty < ActiveRecord::Base
belongs_to :car
belongs_to :property
end
If you have a lot of properties and want to logically separate them then create separate models for each property. Like Engine, Tire, Glass. Each model will contain properties variants. Then create one table for each property to connect it to the car. Like CarEngine, CarGlass. It will contain car_id and property_id (engine_id, glass_id).

Rails Many-to-Many Relantionship Dilemma

I have a User model:
class User < ActiveRecord::Base
has_many :projects, dependent: :destroy
end
and a Project model:
class Project < ActiveRecord::Base
belongs_to :user
end
What should I do if I want a User to be able to fund Projects, and a Project can be funded by many Users?
This would mean I get a Many-to-many relationship, and I would need an additional intermediate table. Call it user_projects:
class UserProject < ActiveRecord::Base
belongs_to :user
belongs_to :project
end
But how do I cope with the previous relationship I had between the models before I implemented the third one?
How do I know which project belongs to which user if I have the intermediate table?
Would I modify the tables the following way?
class User < ActiveRecord::Base
has_many :projects, through: :user_project, dependent: :destroy
has_many :user_projects
end
class Project < ActiveRecord::Base
has_many :user_projects
has_many :users, through: user_project
end
Whether or not you need an intermediate table depends on if there is any associated data you need to store with the user/project pair -- such as a dollar amount or date info or role, etc.
If you don't need to store anything else, then just use a HABTM relationship. Otherwise, your final solution would be the way to go.
I personally don't like the choice of 'user_project' as it's too close to the HABTM's 'users_projects'. Perhaps something like ProjectMember or ProjectFunder or Funding would be better, but it kind of depends on what extra data you need to store.

Resources