Rails Model Property Location - ruby-on-rails

I'm working through the Ruby on Rails tutorial and just made a Comment model with three properties.
rails generate model Comment commenter:string body:text post:references
It generated an ActiveRecord class with post but not commenter and body.
class Comment < ActiveRecord::Base
belongs_to :post
end
Why doesn't rails formally define the non-reference properties anywhere other than the DB migration scripts?

Rails dynamically loads attributes - specifically, the names of the columns and their types - based on the database schema. There is no need to define or declare them in your models. For apps running in production, it does this once, at load time. For development, it will reload them as often as every request, but only loads them when each model is used.
Rails does not infer other things from your database, though. For instance, if you were to place a unique index on a name column, it would not automatically add a validates_uniqueness_of :name to your model. Of course, the database would still enforce this constraint when you save the record, causing an exception to be raised should the name field contain a duplicate value. The recommendation, in this case, is to do both.

Why doesn't rails formally define the non-reference properties anywhere other than the DB migration scripts?
Well, where do you need them "defined" anyways? Migrations are the only place where these attributes matter coz its responsibility is to create database tables with those attributes.
If you do a scaffold on comments with similar parameters, it would also generate the views and it would be using the attributes. They don't need to be "defined" as such anywhere else.

The short answer to your question is "no". Even the migration is not a definitive place to look as there might be many migrations related to a model.
However, you may have a look at the generated "db/schema.rb" which is an aggregation of all migrations. It contains the schema definition of all activerecord models. This maybe your best bet.
Additionally, you may want to use the https://github.com/ctran/annotate_models plugin that inserts a comment in your model to help you keep track of all your model's attributes.

Related

Rails Migration Table

To my knowledge, you specify your model field data types within db/migrations . This is new to me as in Django, you can directly specify your model field data types in the Model class. Am I correct in thinking about this? Is this a common practice in rails or am I just using a work around?
Also, how do you specify table relationships in this db/migrations file. For instance if I have a model that is called class A.
I have another model called class B and I want a one to many relationship with class A. Do I just do
class ClassA < ActiveRecord::Migration
def change
create_table :projects do |t|
t.classB :name
end
end
end
How do I validate that my migration file and my model file don't have any syntax errors. To my knowledge I just run rake db:migrate, but what if I don't want my migration file to be replaced as I specified my field datatypes in the file?
Ok, so all in all you seem to have three questions:
1.: To my knowledge, you specify your model field data types within db/migrations. [...] Am I correct in thinking about this? Is this a common practice in rails or am I just using a work around?
Yes, you are correct about this. Field data types do not show inside the model, only in your migration.
By the way: I rarely find myself writing migration files manually. If you use the rails command, it will generate migration files automatically. For example, if you use
rails g model User first_name:string last_name:string
this will create a model called User, and a migration that will create a users table with the fields id, first_name, last_name, and timestamp fields. If you want to add or remove columns later, there is a nifty trick for that; just run
rails g migration add_fields_to_users field_name:field_type
or
rails g migration remove_fields_from_users field_name.
Replace field_name, field_type and users as you think fit. This command will create a migration for you to add or remove fields, so you don't have to write those manually.
2.: Also, how do you specify table relationships in this db/migrations file.
You don't. Rails handles this for you through association methods like has_many, belongs_to, has_and_belongs_to, etc. Have a look at this rails guide to active record associations. The one thing you need to do on the database side is add foreign_id columns for a one to many relationship or create join tables for a many to many relationship. For example, if you have a users table and a pictures table, and each picture belongs to a user, in your user model you would write has_many :pictures, in your picture model you would write belongs_to :user, and in your pictures table you need a field called user_id with a type of integer.
3.: How do I validate that my migration file and my model file don't have any syntax errors.
You don't either. You just run rake db:migrate, and if something fails, it will tell you where and why. If your model has syntax errors, it will tell you when you start your server, or when you run your tests, or at least when you use it somewhere (e.g., when you call a model's method). If you mean how you validate your model's data, this is a whole other question - refer to this guide to active record validations and callbacks, which explains validations to check for presence, uniqueness, length, etc. in detail.
You have asked several questions, let's go one by one:
To my knowledge, you specify your model field data types within
db/migrations . This is new to me as in Django, you can directly
specify your model field data types in the Model class. Am I correct
in thinking about this? Is this a common practice in rails or am I
just using a work around?
The migrations are used to alter the database. Example of a migration:
class CreateProducts < ActiveRecord::Migration
def change
create_table :products do |t|
t.string :name
t.text :description
end
end
end
When running this, you would be creating a table products with a string field called name. So, yes, you specify your model field data types in the migrations.
Also, how do you specify table relationships in this db/migrations
file. For instance if I have a model that is called class A.
You need to specify your relationships (or associations) in your models. Read this, because it is really well explained. But take into account that in the migrations somehow you have to do some work to create the associations because you might need to create join tables for many to many associations, or create a column that references another table for a has_many association.
How do I validate that my migration file and my model file don't have
any syntax errors. To my knowledge I just run rake db:migrate, but
what if I don't want my migration file to be replaced as I specified
my field datatypes in the file?
I am not sure what you mean in this question.
When you create a new model rails creates your shema migration files and your model.
In the migration file you specify your columns. It is possible to add some code here but you should do as less as possible. For up and down you add/remove columns here, add db indexes and so on.
In your model you define your relations belongs_to, has_many, etc. and your scopes for your tables and ofc the methods for your model. Your model inherit your table columns so you can access them directly.
I don't know Django, this is the common practice in rails.
Relations and other good infos you can check here: http://www.tutorialspoint.com/ruby-on-rails/rails-models.htm

Rails Generating Migrations From Model

I've been reading about Rails Migrations to help me start building a rails project.
I'm a bit confused on the generation of the files in db/migrate.
The way I've been designing my application is by starting with the models... outlining all of the objects that I'm going to have in the system as best I can. I would like to generate the migration files FROM these models automatically with the rails migration generator.
Yes, I know "creating migrations manually is easy." And I know I could do it manually, but what I don't understand is why the tool is separated from the pre-created models.
Based on my understanding from the article and other migration questions on SO, I can generate a migration like so:
rails generate migration SomeObj field:string some_other_field:integer
What I don't get is why I need to pass in the fields when my model already exists for SomeObj? Couldn't Rails detect it from the some_obj.rb and create the migration from there?
Also, when I have a more complex model, with has_many, belongs_to, and has_to_and_belongs_to_many relationships, it would be really nice if it autocreated the JOIN tables and fields with the correct names (e.g. foreign_obj_id, foreign_obj_ids)
In a previous project I didn't have to deal with migrations because I used Mongo+Mongoid - and collections were automatically generated due to the nature of how Mongo works (collections that doesn't exist get automatically created upon inserting or updating). Now with this Rails app I'm using Postgres (but I'm sure the same thing would happen with MySQL or any other relational database).
Anyway, is there no helper for this kind of thing? Do I have to create all these migrations manually?
You've got this backwards. You need to build your migrations first, and your models second. Migrations advance the state of the database. Your models reflect the current state of the database. There is not a 1-to-1 mapping of models to migrations.
I would like to generate the migration files FROM these models automatically with the rails migration generator.
Can't be done.
You use rails generate migration to generate the migration, which, almost as a side-effect, generates a stub model file. You cannot use your existing model file to generate the model's migration, because the model doesn't contain any information about the actual columns that make up the model. Rails would have to extract and imply all the necessary information from your associations/validations, and even then it would get most of the columns wrong.
Also, when I have a more complex model,... it would be really nice if it autocreated the JOIN tables and fields with the correct names
Again, you can't. You're responsible for defining your database schema, and the way you do so is by building migrations. You can do so manually, or via rails generate, but the process you should be following is building your migrations first, and your models second.
By way of example, here is a complete model, ready for production:
class MyModel < ActiveRecord::Base
end
That model definition might wrap a table that contains 10 columns or 1000 columns; you (and Rails) have absolutely no way of knowing based on the model definition.
Here's another model, which contains at least one column, but again, you have no way of knowing what kind of column:
class MyModel < ActiveRecord::Base
validates :code, presence: true, uniqueness: true
end
Is code a string or a number? Should there be an index on the column? There is absolutely no way of knowing.

What is the common way to define models in Rails application?

All of the tutorials I've seen so far for RoR have shown me generating models like:
rails generate User name:string placeofbirth:string
This generates a class for the model, and only actually references an attribute if I apply a validation of some kind.
So my question is, how do I use a 'code' first approach when creating my models. Or is it the rails way to just right down on paper the attributes you want, run the generate command with each attribute you want and it's type, then run the rake db:migrate command?
I'd love some more proven patterns on this subject because so far the way I've seen seems too empty.
Yes, this is the rails way- migration comes first and generates the code and the database- and the model class inspects the database to see what fields are there and make accessible via methods.
You can do gem install annotate_models if you want to get some comments in your model class with the attribute names and types.
See here for an example: https://github.com/ctran/annotate_models
Rails uses an active record pattern for models which basically means that a model object will automatically map each DB column to an attribute so you don't have to specify all attributes in the model. It's a feature, but I agree that it might not be perfect for everyone. If you're using Rails 3 it should be easy to use another ORM of your choice if ActiveRecord's approach doesn't suit you. Here are some alternative ORMs that you could use.
Usually when you are developing some database backed web application, you know the database design(name of the tables, name of the columns in those tables and associations between different tables) beforehand.
Rails, as mentioned by maarons in his answer, uses Active Record pattern. Your models are classes that represent a table in your database, an instance of your model class a row in that table and different attributes of an object represent values under different columns in the same table.
When you create a model, usually, you are creating a class that represents one of the tables in your database. And while you are creating a model, you are also going to create a table in your database. That means knowing the name of the table and columns within that table.
So to answer your question, you must know all the columns, required for the time being, that will be in your tables. And hence available as attribute methods for your model objects. You specify these columns to added in the table in the migration generated by rails generator while generating this model. This is what usually everyone does.
You can take a code first approach by creating a class, without running the rails model generator,under app/models/ but not inheriting it from ActiveRecord::Base. As you move forward in your development, you can generate migrations by $ rails generate migration MigrationName and creating table and adding columns using [add_column][2]to that table as required. Once you have created a table for this model, you will have to inherit that model from ActiveRecord::Base so that you can get all the Rails magic in your application.

Creating readable models in rails

I have just started with Rails and coming from a .net background I find the model inheriting from ActiveRecord is hard to understand, since the don't contain the corresponding attributes for the model. I cannot imagine a new developer exposed to a large code where the models only contains references to other models and business logic.
From my point of view the DataMapper model is much easier to grasp but since ActiveRecord is the defacto standard it feels weird to change the ORM just for this little problem.
DataMapper
class Post
include DataMapper::Resource
property :id, Serial # An auto-increment integer key
property :title, String # A varchar type string, for short strings
property :body, Text # A text block, for longer string data.
property :created_at, DateTime # A DateTime, for any date you might like.
end
ActiveRecord
class Post < ActiveRecord::Base
end
I'm not sure if this is an issue and that people get used to the models without attributes, or how does experienced rails user handle this?
I don't think using the database manager or looking at loads of migrations scripts to find the attributes is an option?
Specifying attr_accessible will make the model more readable but I'm not sure if it's a proper solution for my problem?
Check out the annotate_models plugin on github. It will insert a commented schema for each model in a comment block. It can be installed to run when migrate is.
You don't have to "look at loads of migration scripts to find the attributes" - they're all defined in one place in db/schema.rb.
A few tips:
Load up the Rails console and enter
Post.column_names for a quick
reminder of the attribute names.
Post.columns gives you the column
objects, which shows the datatypes
db/schema.rb contains all the
migration code in one place, so you
can easily see all the column
definitions.
If you are using a
decent editor/IDE there should be a way to
allowing you to jump from the model file
to the migration file. (e.g. Emacs
with ROR or Rinari)

Ruby on Rails working with pre-existing database. Rails makes everything plural

What is the deal with this? I'm working with a pre-existing that I did not do myself. Everything in the database is labeled in singular form. user, security, spec, etc. I guess the right way would be users, securities, specs. At least that's what ruby on rails try's to lookup when I generate a scaffold .
How do I specifically state to use user instead of users in the sql. I don't see anywhere in my project where it is looking up the sql. I mean if my model is user you would think it would try to lookup user. Instead of users.
Thanks for any help.
You need set_table_name :name_of_the_table in your model (source).
So:
class User < ActiveRecord::Base
set_table_name :user
end
The reason they use plural for the table and singular for the model is because an instance of the model represents one user, whereas the table contains all the users. It's just to make it more readable and logical.
You can specifiy the table name:
How do I explicitly specify a Model's table-name mapping in Rails?

Resources