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.
Related
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.
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.
I have an article model article.rb (with related images):
attr_accessible :name, :content, :image_ids, :altname1
I now want to create another kind of articles, that are just for cities. They will appear in a completely different section of the website and are not related to all other articles. But the model is exactly the same.
Is it better to create a new model cityarticle.rb or is it better to add a new boolean column (cityarticle with true and false as options) into the existing article model. I'd then add a new action to the controller:
def cityarticles
#cityarticles = Article.where("cityarticle = ?", true)
end
For me it's easier to keep just one model, but there might be good reasons for a new model? How about performance?
Some questions to ask yourself: In what other ways will these types of articles be different? Will different people have access to create/edit/delete them? How do I create a city article and not let it accidentally be saved as a non-city article, or vice versa? Am I using attr_accessible or strong_parameters to prevent users from overriding the article type with params passed in? Will the different types have different validation rules (maybe requiring a city name for city articles)?
How hard will it be to get just the articles I want? How likely am I to forget to specify what kind of articles to show and show all of them?
Based on answers to questions like those, you should be able to decide what data structure will work best for you. If you use Rails' STI pattern, you could wind up with one table but two different models, as one solution. Performance is probably not the main consideration, but if the two types of articles are never going to be queried together, it might be slightly better in terms of performance to split them into separate tables.
New model represents a new "entity" on the System.
Say CityArticles extends Article
It should be a new Model for code clarity and extensibility to increment functionality over the "CityArticles".
You can make a new table scaffold or migration:
rails g scaffold CityArticles references:article
Or making Article class polimorfic association. Read http://teachmetocode.com/articles/ruby-on-rails-what-are-polymorphic-associations/
I want to aggregate data from different sources, Twitter lastfm and that sort. I just can't figure out how to store the data. Clearly in a database but I can't figure out how abstract to make the table to hold all this data without compromising the logical understanding of the data in each column.
I was wondering if anybody else had experience with this and now they tackled it in rails.
One option, if you want to stick with SQL, would be to have a Model/Table which contains fields common to every data source (title, url, summary) which is associated to other Models/Tables which contain the fields specific to individual data sources. The associations could be regular or polymorphic. And if you wanted to get in to some metaprogramming you could use method_missing to delegate method calls for fields not present in the 'common' Model to the associated models. This would work best with a polymorphic join. Psudeo-code:
class DataSource
belongs_to :data_source_extension, :polymorphic => true
def method_missing(method)
if data_source_extension.responds_to? method
data_source_extension.send(method)
else
super
end
end
end
The other option would be STI, so one table with all fields and a 'type' field which tells Rails which model the record should be wrapped in. This depends on how many different sources you have and how different they are from each other.
If the fields don't need to be searchable storing a Hash in a Text field works well. See Serialize and the attr_bucket gem.
Or if you want to trendy a NoSQL type database allows on-the-fly fields to be generated.
What you need is a document-oriented database (I recommend you MongoDB), and then having a set of adapters, one for each type of provider.
Document oriented database
I have a user table, and a teacher that I newly created. The teacher is sub class of user, so, I use scaffold generator to generate the teacher table, than, I modify the model to do teacher is subclass of user. After all that, I did a db:migrate. Then, I go to
http://localhost:3000/teachers/new
It shows an error:
undefined method `teacherSalary' for #<Teacher:0x103331900>
So, my question is what did I do wrong? I want to create a page for doing user register, the user can ONLY be a teacher / student. But I can't add a teacher record ... ... Moreover, I go to
http://localhost:3000/users/new
I want to have a combo box that allow user register their user to be a "teacher" or a "student". But everything seems not work like I expected. What I need to do? Thank you very very much for your help.
Within your database you should have a single table called users. This table should have a string column which by default is called type. If you use another name for this column then you will have to set the inheritance column name manually using self.inheritance_column = "column_name"
Within your application you have three models, User, Student and Teacher. User inherits from ActiveRecord::Base as usual, Student and Teacher both inherit from User.
You should then be able to instantiate new Teacher and Student objects. Internally this works by writing the model name to the type field on the user tables and then when you use Student.find it adds a clause to the SQL to only return rows where the type = 'Student'
You can add shared behaviour to the User class, e.g. validations etc then add additional behaviour to the inherited classes.
A fuller description of how STI works can be found in Martin Fowlers Book(Patterns of Enterprise Application Architecture).
I found this definition really handy:
STI means one table contains the data of more than one model, usually differentiated by the "type" column. ("users" table contains data for the models "Teacher", ""Pupil", "Employee", "Assistant", etc.)
Keeps similar models in the same table instead of creating new ones.
A Polymorphic Association means that one model can be associated with more than one other model(Comment can belong to post, image, file, user_type...)
To prevent foreign key conflicts, the association is reperesented with the *_id and *_type columns instead of only *_id.
For what you have here , I am not sure if STI is the best way go . STI should generally be used when there is a OO like inheritance and the Models have the same Attribute but different behaviour . In your case Teacher and Student can sure have a few shared attributed , but they are also bound to have different ones as well .
You might want to experiment with a polymorphic association as well .