rails when/how to use nested resources - ruby-on-rails

I have a rails app. Users can create products that will be listed on products index page (including some data about the user who posted it) and everybody can see the list on app/products.html.
What is the best way to implement this? Should I do it with nested resources (user has many products) in which case I can use product.user.name for displaying the user name or should I create an independent class so when user creates a product, some user attributes (name, etc.) will get saved in the product table.

Your mixing together quite a few different concepts here.
Nested routes
In REST you have a concept of nested resources which is expressed though URIs such as:
posts/:post_id/comments # comment that belong to a resource.
Which tells us that there is a "has many" relation between post and comments.
The best practice here is that:
Don't nest if you don't need to.
Never nest more than 1 level deep. posts/:post_id/comments/:comment_id/replies for example should be comments/:comment_id/replies.
Associations and domain modeling
Domain modeling on the other hand is how your models fit together. In ActiveRecord each model class is backed by a database table.
Each model should correspond to a single type of object in your problem domain. So in your case you would have a User class and Products class.
They would be linked by a products.user_id column. So no - you should not store users attributes in the products table.

Related

Managing polymorphic data in Rails

I have an application where a User can create many Links, and each Link can store different type of data, depending on what type of Link it is. For example, a TelephoneLinkData stores a telephone number, an EmailLinkData stores an email address, a subject and a body. Each Link also has some fields in common, such as a reference to the user and a name.
I've tried to map this into ActiveRecord as cleanly as I can. Currently, I have a polymorphic relationship from Link to its data-type:
class Link < ApplicationRecord
belongs_to :user
belongs_to :link_data, polymorphic: true
...
class EmailLinkData < ApplicationRecord
has_one :link, as: :link_data
accepts_nested_attributes_for :links
...
Technically, I think this would be described as a reverse polymorphic relationship as instead of a class having possibly different parent classes, what I'm trying to model is a class having multiple possible different child classes. This works fine, and I'm able to create Links through the various *LinkData controllers, but what I'd really want to do is have the Link act as the primary source of interaction for the user, so that the user manages their links through the /links path. For example, I would like the API to allow a User to create a link by posting to /links with the data for the LinkData nested in the link_data field
I've looked around for other ways to model this relationship, and the most common other suggestion seems to be Single-Table Inheritance, but the majority of my columns will differ between LinkData classes, so that feels like the wrong abstraction.
Is there a more idiomatic way to model this data structure?
As is always the case, the best choice depends on the business or application needs, so it's difficult to provide a recommendation without knowing more about what you're trying to do.
It sounds like you prefer the MTI approach, essentially using actual foreign keys and an XOR constraint to the Link table instead of a type column. That's a totally reasonable (although not as common) alternative to a polymorphic association.
However, I think there was a bit of a misunderstanding in your question.
Technically, I think this would be described as a reverse polymorphic relationship as instead of a class having possibly different parent classes...
A polymorphic association in Ruby/Rails doesn't have anything to do with class inheritance (e.g. parents and children). You might be thinking of Single table inheritance. A polymorphic association allows one class (e.g. a Link) to be associated a record in any other table (e.g. the various classes of LinkData) via two fields, a association_id and association_type. These associated classes need not be related to each other. For example, a common use case might be the acts_as_commentable gem, that allows you to add a comment to any other object, and the comment would have a polymorphic association with the other classes.
In the second part of your question you mention that you'd like the User to interact with Link's via a single controller.
I would like the API to allow a User to create a link by posting to /links with the data for the LinkData nested in the link_data field
There's nothing stopping you from implementing this using the initially proposed data model. ActiveRecord may not handle this completely for you out of the box, but you can imagine implementing a link_data= method on the Link class that would create the appropriate associated object.
I'd say the pros/cons of using a polymorphic association would be...
Pros:
easy to setup and use
easy to make required (validate presence of / not null)
easy to associate with a new class
Cons:
no referential / database integrity
have to migrate data if you change a class name
And using the MTI approach is basically the opposite. A bit harder to setup and use, harder to add a new association/table, harder to ensure exactly one association exists... but the long term data quality benefits are significant.
I was able to get things to work the way I wanted to using multiple table inheritance, based largely on this chapter: https://danchak99.wordpress.com/enterprise-rails/chapter-10-multiple-table-inheritance/

Proper way to set up a Trainer/Member relationship using one entity

I am modelling a Trainer/Member relationship on Ruby on Rails and I was wondering what is the best way to model this relationship.
Currently I only defined roles for a User class using Rolify for view and controller access.
Trainers and Members are users.
Should I do a recursive relation between the User model, or should I create a Trainer and a Member model specifically on Rails, and set up hierarchy between them, and create the relationship between the child models?
I would setup two different models for trainers and members as you proposed and use the rails association helpers. For example, if a member can have several trainers and trainers can have many members you would want to implement a many-to-many relationship. This is most easily done in rails via the "has_many :through" model helpers. You can then add an attribute to these classes that would specify the levels of authorization or controller access on your app if need be.

How to implement a HABTM in Ember?

Ive got the same HABTM (has many and belongs to many) as described at http://guides.rubyonrails.org/association_basics.html#the-has-many-through-association
In ember-data, how does one define the relationship between physician, appointment and patient?
In Rails, it is easy enough via has many through. Or, is there no need to do a HABTM association in Ember, since it is pulling/sending data out from/to an API?
Unfortunately, http://emberjs.com/guides/models/defining-models/#toc_many-to-many shows a many-to-many association with TWO models only.
Well, at a minimum you're going to need to add a couple of belongs-to relationships on your appointment model:
App.Appointment = DS.Model.extend({
...
physician: DS.belongsTo('physician'),
patient: DS.belongsTo('patient'),
...
});
Thus, whenever an appointment is saved, its child relationships will be saved with it. I assume that's what you want, since that's how the db is structured in the link you posted to the Rails guide.
The rest depends heavily on how your application is structured, especially your server's JSON API. For example, if you've got a model physician and you might be able to do something like this:
var query = { physician: physician.get('id') };
this.get('store').findQuery('appointment', query).then(function (results) {
...
});
If you then wanted to find all of a physician's patients, you could simply return an array of the unique patients belonging to the appointments that were found. This approach is pretty straightforward and easy to reason about, but it doesn't take full advantage of Ember Data.
Alternatively, you could try defining a has-many relationship on your physician and patient models: appointments: DS.hasMany('appointment'), which has some advantages but also requires much better knowledge of Ember Data.

Create form for multiple models in Rails

I'm very new to Rails so sorry in advance if this is a fairly obvious question.
I need to make a form that can create records for multiple models in Rails. My models are categories of grocery-store items: Produce, Meat, Dairy, etc.
In my create form, I want the user to be able to create a product by selecting which model it belongs to and then have the controller insert the record into the appropriate DB table.
so my questions are:
should I still define each model as a resource?
is it possible to use one controller to add, update, delete for all of the product models?
Have you considered just making a category column in your items model? If not you could use active record associations to accomplish something like this. See the documentation at:
http://guides.rubyonrails.org/association_basics.html

Access Attributes of a "related" model from the first

I have a rails application that has several models. One particular model is the "focus" of the application, and it has several one to many, and several many to many relationships defined.
I have created logic to export the fields to a CSV file, and within the model I have defined a couple methods someone showed me to facilitate this. Here are the two methods:
def self.csv_header
fields = attr_order.*.to_s & content_columns.*.name
fields -= %w{created_at updated_at created_on updated_on deleted_at}
fields.reject! { |f| never_show? f }
fields
end
def to_csv
self.class.csv_header.map { |h| send(h) }
end
However, in my primary model (called patient) I need to include fields from some of the other one-to-many models (e.g. home_address, which contains street, city, state, zip, etc.). Is this possible to keep inside the patient model? I have set up logic in my controller which can add the other model's information, but it seems like it would be much cleaner to let the patient model grab all the additional information it needs from the other models and add it to the export rows.
Most of your work should be done in the models anyways, in my opinion. Keep the controllers thin, and the models fat, vs the other way around.
If you need to then access some attributes - say Patient has a 1-to-1 relationship with Address, then feel free to do so! Just do something like the data something like:
fields += HomeAddress.csv_header
home_address.rb
def self.csv_header
... pretty much the same thing as Patient.csv_header
end
So, you're not keeping the data in the Patient model, but rather, you're keeping the data where it belongs and just being able to access it.

Resources