Rails Migration Table - ruby-on-rails

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

Related

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.

Ruby on Rails: how to migrate changes made on models?

In a Rails application, how can I migrate the changes I make in models? For instance, I know that if I create a model with command "rails g model Person name:string", a migration will be created as well. However, if after this step I go to the created model "Person" and add a new attribute, will this new attribute be automatically added to a migration for later persistance in database?
Or am I looking at this from the wrong side, and an attribute should be added to a migration, and then added to a model?
Regards
You can't really "add" an attribute to a model, you do that by creating the migration file and running it -- Rails figures out what attributes a model has based on what columns are in the database. However, you do need to add a line to the model to whitelist the attribute if you want to be able to update it via mass assignment. That's why you'll often see a line like this in activerecord models:
attr_accessible :name
But that's optional and not essential to adding the attribute.
To actually add the new attribute to your model, first create a migration with:
rails g migration AddAddressToPerson address:string
That will create the migration file in the db/migration/ directory. (The form “AddXXXToYYY” and “RemoveXXXFromYYY” are understood by rails to mean "add (or remove) a new column to the model XXX", see the documentation for details). In this case I've added an attribute named address which is a string, but you could change that to whatever you want it to be.
Then to actually update the database, you need to run the migration with rake:
rake db:migrate
Finally, if you want to allow mass assignment on that attribute, add the attribute to your list of arguments to attr_accessible:
attr_accessible :name, :address
That should do it.
If you are adding the new attribute with attr_accessor, you will not need to do anything with migrations, but your changes will not be stored in the database.
If you do want to persist your changes, you will need to add the attribute to your model using a migration. You can just create a text file, with the proper structure, migrations are nothing fancy, but it is a lot easier to generate on like this rails generate migration AddLastNameFieldToUsers. The contents of such a file might be adjusted to look like this:
class AddLastNameFieldToUsers< ActiveRecord::Migration
def change
add_column :users, :last_name, :string
end
end
You don't need to add attributes directly to the model. Rails (actually ActiveRecord) infers it automatically. For the list of attributes for the model class, AR looks for a table with a plural form of the model's name (if model is Order, then it will look for attributes in the orders table). It is part of the design feature called CoC - Convention over Configuration.
So you if you have to add an attribute, you have to create a migration to add that field into the column as mentioned in other answers.

Rails Model Property Location

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.

Rails: define column names to model

I have an existing database(Postgresql). How can i create models from it? How can i pass column names for Rails? As if something like this:
Person:
Name :table_name_for_name_attribute
Surname :table_name_for_surname_attribute
PersonalCode :table_name_for_perconal_code_attribute
Unfortunately, my database is not following Rails convention, because not all tables are named in English. Any ideas how can i map it?
UPDATE reverse_scaffold script generates only model, but i need controller and view forms also.
You can define a table name not matching the model's using the table_name method.
class MyModel < ActiveRecord::Base
def self.table_name
'my_table_name'
end
end
Change the value of 'my_table_name' to your effective table name.
For generating controllers and views with automatic methods to create, update, delete and view database objects, you should create a scaffold. There's some pretty good documentation on the rails guides about that.
In your model, you'll need to tell ActiveRecord what the table name and primary key field column is named if they don't follow the conventions.
class MyLegacyTable < ActiveRecord::Base
self.table_name = "some_name"
self.primary_key = "some_name_primary_key_field"
end
Once you've done that, ActiveRecord knows the some_name_primary_key_field as id, which makes life much easier.
Rails doesn't need to know the column names it figures them out when it connects to the database.
As others have said you can specify a table name in the model.
As for generating controllers/views, you're pretty much own your own. script/generate scaffold is deprecated. It still works as far as creating things, but you need to pass all column names and times on the command line.
Instead have a look at the ActiveScaffold Plugin, it has a similar end result. But is much more robust and easier to adapt to model changes.

What does a db table created by the Rails framework look like?

I don't have a Rails environment set up and this is actually quite hard to find a quick answer for, so I'll ask the experts.
When Rails creates a table based on your "model" that you have set up, does Rails create a table that mirrors this model exactly, or does it add in more fields to the table to help it work its magic? If so, what other fields does it add and why? Perhaps you could cut and paste the table structure, or simply point me to a doc or tutorial section that addresses this.
If you're building a completely new application, including a new database, then you can build the whole back end with migrations. Running
ruby script/generate model User name:string
produces both a user.rb file for the model and a migration:
class CreateUsers < ActiveRecord::Migration
def self.up
create_table :users do |t|
t.string :name
t.timestamps
end
end
def self.down
drop_table :users
end
end
You can see that by default the generate script adds "timestamps" for (created and last updated) and they're managed automatically if allowed to remain present.
Not visible, but important, is that an extra column, "id", is created to be the single primary key. It's not complusory, though - you can specify your own primary key in the model, which is useful if you're working with a legacy schema. Assuming you retain id as the key, then Rails will use whatever RDBMS-specific features are available for new key values.
In ActiveRecord, models are created from database tables, not the other way around.
You may also want to look into Migrations, which is a way of describing and creating the database from Ruby code. However, the migration is not related to the model; the model is still created at runtime based on the shape of the database.
There are screencasts related to ActiveRecord and Migrations on the Rails site: http://www.rubyonrails.org/screencasts
Here's the official documentation for ActiveRecord. It agrees with Brad. You might have seen either a different access method or a migration (which alters the tables and thus the model)
I have had a little experience moving legacy databases into Rails and accessing Rails databases from outside scripts. That sounds like what you're trying to do. My experience is in Rails databases built on top of MySQL, so your mileage may vary.
The one hidden field is the most obvious --- the "id" field (an integer) that Rails uses as its default primary key. Unless you specify otherwise, each model in Rails has an "id" field that is a unique, incremented integer primary key. This "id" field will appear automatically in any model generated within Rails through a migration, unless you tell Rails not to do so (by specifying a different field to be the primary key). If you work with Rails databases from outside Rails itself, you should be careful about this value.
The "id" field is a key part of the Rails magic because it is used to define Rails' associations. Say you relate two tables together --- Group and Person. The Group model will have an "id" field, and the Person model should have both its own "id" field and a "group_id" field for the relationship. The value in "group_id" will refer back to the unique id of the associated Group. If you have built your models in a way that follows those conventions of Rails, you can take advantage of Rails' associations by saying that the Group model "has_many :people" and that the Person model "belongs_to :group".
Rails migrations also, by default, want to add "created_at" and "updated_at" fields (the so-called "timestamps"), which are datetime fields. By default, these take advantage of the "magic" in the database --- not in Rails itself --- to automatically update whenever a record is created or modified. I don't think these columns will trip you up, because they should be taken care of at the database level, not by any special Rails magic.

Resources