I'm wondering if there's such a thing as a best practice for one to many relationships. I'm planning a simple rails app that will have a relational DB with either of the following scenarios:
Scenario A ERD: A user can have zero or many lists, and a list can have zero to many items. I know that this means a user cannot directly create an item. An item can only be created through a list. An item actually belongs to a list, and a list belongs to a user.
Scenario B ERD: A user can have zero or many lists, and the user can also have zero or many items. This means everything is directly associated to the user. Items will be associated to a list due to a foreign key via a list ID.
Is there a best practice to use/not use either scenario?
Thanks in advance!
Scenario A is a better approach.
class User < ActiveRecord::Base
has_many :lists
has_many :items, :through => :lists
end
class List < ActiveRecord::Base
has_many :items
end
Related
I'm trying to figure out what the appropriate ActiveRecord associations would be for my models. I am building a meal customization and ordering system for a website where Users can select from a number of Items and build a Meal and repeat this multiple times for a single Order.
My current setup is as follow:
User
has_many :orders, :dependent => :destroy
has_many :meals, through: :orders
Order
belongs_to :user
has_and_belongs_to_many :meals
Meal
has_and_belongs_to_many :orders
has_and_belongs_to_many :items
Item
has_and_belongs_to_many :meals
I suppose my question then would come in two parts:
1) does my current setup allow for multiple items to be assigned to a single meal, and possibly to other meals for a single order.
2) will I be able to access a user's previous meals to provide a shortcut when making new orders.
thanks a bunch in advance from a first time question asker!
To your first question, yes, you have set up a many-to-many relationship between your meals and items (assuming you have the correctly named database columns as well).
To your second question, you may have to wright a custom query for it as I'm not sure if active record is setup to do the multi layer query you're asking it to do (i.e. get all the meals from all the orders for a given user). Something like
past_meals = Set.new
users.orders.each {|o| past_meals += o.meals} would certainly work but could be made much more efficient if you needed it to.
However, even though has_many_and_belongs_to does work for what you're doing, using it isn't recommended. The community is much more in favor of making a join table doing a has_many_through relationship with that.
You in no means have to do that but most people would suggest it and it could save you some work down the road.
I have a model "entry" and I need it to act like a list when a playlist_id is specified, but if it's not, I need it to not act like a list. (acts_as_list is a gem I'm using)
In my model code I have:
acts_as_list scope: :playlist
I need to figure out the best way to do this. I'm thinking of subclassing a model maybe, but I'd prefer to just keep it as one model but add this additional logic. I don't know the order of initialization for active_record so I'm not sure where I could mess with things like this and where I can't.
(The reason why I need to do this: I want to have loose items that belong to another model, simply sorted by date. As my "default list" has grown in size, I'm experiencing some performance issues since we have to look up the last entry in a list to know the position of the newest item.)
My shallow understanding is the model projection may need improvement. In my understanding act_as_list is better for has_many - belongs_to relationship, say a todo is exactly in a Todo list.
But in your case, let's say the entry is a song. A playlist can have many songs and a song can belongs to many playlist. So the relationship is many to many.
I think you need an intermediate model say ListItem to represent such relationship
class PlayList < ActiveRecord::Base
has_many :list_items
has_many :entries, through: :list_items
end
class ListItem < ActiveRecord::Base
belongs_to :play_list
belongs_to :entires
acts_as_list scope: :play_list
end
class Entries < ActiveRecord::Base
has_many :list_items
has_many :play_lists, through: :list_items
By this design, what you sort on PlayList is only the list items, not the entries. Performance should be improved a lot as longs as on playlist doesn't contain too much list_items, which should be common.
I'm new to RoR, and I'm trying to create my first association within my app between an Order model, and a star key that represents all of the users who have starred that particular order.
I was originally thinking of using a has_and_belongs_to_many association for this, but that doesn't make sense given that there aren't many stars coming from the one user to one order.
With that said, I've really confused myself and could use a little bit of direction. Perhaps a simple migration file would send me down the right path.
Cheers!
Assuming users can "star" more than one order, then you do indeed want has_and_belongs_to_many. You can readily enforce that any one user has only one relationship to any one order.
I would indeed create an in between table referencing both Order and User, as an order has many users that keyed the order, and a user can key many orders...
rails g migration CreateOrderUsers order:references user:references
Your order_users model becomes
belongs_to: order
belongs_to: user
Then put in your order model
has_many :order_users, dependent: :destroy
has_many users, through: :order_users
And in your user model
has_many :order_users, dependent: :destroy
has_many orders, through: :order_users
Hope this helps!
Please forgive me if this has been answered already but I've searched a lot and still require some clarification.
I'm building a Property Management tool using Rails 3.2. I already have a User model and authorisation/authentication code in place with full tests coverage.
I've just started drawing out the models/classes/tables and have gotten myself a bit confused.
Let's start with Users.
Modelling Users
I plan to have allow multiple companies to use this system. Each will have employees (users). These users will have different roles e.g. Manager, Agent, Accountant, Secretary etc. For the most part the data I plan to store for each of these users will be similar (or so I think at the moment) so I am leaning towards Single Table Inheritance and using the type to define the level of access each employee has.
Secondly, I plan to allow Landlord and Tenants to also log in to the system. Upon logging in they'll be able to view information about the property they are owning or renting - maybe keep their contact details up to date too.
I was thinking of using polymorphic associations to represent these users.
So the plan I have at the moment and would like some feedback on is to have
User < ActiveRecord::BASE
Employee < User (this will have a STI type column and allow for the different employee roles)
Landlord < User
Tenant < User
Is this the best way of approaching this problem or am I shooting myself in the foot?
I've had some people advise me I should have a 'roles' table and assign roles to the users - but I have a feeling this isn't the most elegant way to do this in Rails.
Properties
My next issue is with Properties. Right now I have a model for properties and when I add them they belong_to a User (i.e. they have a user_id foreign key). I then started thinking "what happens if the employee (user) that added the Property leaves the company or has their account deleted for some reason?"
So in this scenario is it best to forgo the User/Employee to Property association and just link the Property to the Company that the employee belongs to? This way I can all employee.company.properties to list out all the properties?
Landlord and Tenant associations
Let's presume we make Properties belong to a Company.
In terms of associations this is what I have in my head. Looking at it now I see that everything belongs to a company because one company using the system shouldn't be able to see the landlords/tenants/employees/properties of another company.
class Landlord < User
belongs_to :company
has_many :properties, :through => :ownerships
end
class Tenant < User
belongs_to :company
has_one :property, :through => tenancies #you can only live at one place at a time right?
end
class Property < ActiveRecord::Base
has_many :tenants, :through => :tenancies
has_many :landlords, :through => :ownerships
belongs_to :company
end
class Company < ActiveRecord::Base
has_many :properties
has_many :employees
has_many :landlords :through => :ownerships #not sure if through is required/works here
has_many :tenants :through => :tenancies #not sure if through is required/works here
end
class Employees < User
belongs_to :company
end
Properties
Also I'm guessing we'll have different types of Properties (Commercial/Residential) and of those there will be whole buildings, apartments within a building (single address) etc.
Like with users I'm planning on using Polymorphic Associations to define two subclasses CommercialProperty and ResidentialProperty and then use sti to define a type. If the type is "multi unit" then have a new model for units and an association whereby Property has_many Units and a Unit belongs_to a property.
Aim
I'm trying to make sure that my code follows best practice as much as possible so that when I come to add new features and expand I'm not left having to re-write large chunks of the app.
I would really appreciate your feedback.
Reference
Some of the posts I've read. Hopefully to help others trying to solve the same problem.
Designing a Rails application: single table inheritance?
Ruby on rails with different user types
Ruby On Rails User Model for multiple types
It's probably too late but you could also use has_and_belongs_to_many on User and Company and thus avoid STI altogether by using gems cancan and rolify.
It allows you to define finely grained access rights (abilities).
I know that it seems more elegant having different classes instead of roles, but it is not viable long-term strategy, it can become messy when logic becomes complex.
Other then that, the rest seems pretty solid, hope that helps :)
I am building an inventory management application with four different user types: admin, employee, manufacturer, transporter. I haven't started coding yet, but this is what I'm thinking.. Manufacturers and transporters are related with has_many :through many-to-many association with products as follows:
class Manufacturer < ActiveRecord::Base
has_many :products
has_many :transporters, :through => :products
end
class Product < ActiveRecord::Base
belongs_to :manufacturer
belongs_to :transporter
end
class Transporter < ActiveRecord::Base
has_many :products
has_many :manufacturers, :through => :products
end
All four user types will be able to login, but they will have different permissions and views, etc. I don't think I can put them in the same table (Users), however, because they will have different requirements, ie: vendors and manufacturers must have a billing address and contact info (through validations), but admins and employees should not have these fields.
If possible, I would like to have a single login screen as opposed to 4 different screens.
I'm not asking for the exact code to build this, but I'm having trouble determining the best way to make it happen. Any ideas would be greatly appreciated - thanks!
Your basic approach seems reasonable. I would advise you to make a base class of User and use STI for specific User types, for instance:
class User < ActiveRecord::Base
end
class Manufacturer < User
has_many :products
has_many :transporters, :through => :products
end
...etc. This way if there's ever the need to aggregate multiple user types into one relationship regardless of type, you have one table to describe Users in general. This is a fairly common approach.
Depending on how much access different users will have to the system, you may want to look at a Role Management gem like Declarative Authorization.
For Multiple user systems, generally preferred ways are - use of role model or STI. If your users can have multiple roles at same time, like single user being Manufacturer and transporter, then Role base system would be good solution. If users role is fixed, then i think you should go with STI.
I suggest you make a User model, Address model, ContactInfo model, etc. You should NOT have those kinds of fields in the User model. Normalize the database. Have a FK in each of those other classes to User.id.
If you MUST keep them separate, then normalize logins and make it polymorphic to reference its owner (manufacturer, employee, etc)