Rails rename the ID column in a model - ruby-on-rails

I'm currently looking at migrating an existing system (written in spaghetti PHP) over to rails. The problem is, it has to run off of a live database. A lot of the ID columns on these different tables aren't named id. For instance, the customers table has an ID column called Customer_ID. Upon looking, I just realised that rails does infact seem to find by the primary key instead of a specific column called id.
Will I face a lot of problems later with the naming of these ID columns, specifically in stuff like relationships?

After v2.3.8, set_primary_key :col_name is deprecated.
self.primary_key = 'col_name' is recommended.
http://api.rubyonrails.org/classes/ActiveRecord/AttributeMethods/PrimaryKey/ClassMethods.html

Change primary key attribute in model by using
set_primary_key :col_name

Related

Is data integrity important when using Ruby on Rails ActiveRecord's associations?

I'm just playing with RoR and I've noticed that ActiveRecord associations such as has_many or belongs_to are decoupled from the database running behind, i.e., these association are set regardless of the the constraints set by the database. For example, I have a table comments and a table users and they are related through has_many and belongs_to statements (a comment belongs to a user and a user has many comments). However these associations still let me assign a comment to a, for example, non-existing user. The reason of this is that there's no foreign key defined in the database.
My question is: should I just rely on ActiveRecord's associations to handle data integrity or should I also add foreign keys in migration files?
Thank you.
Rails holds some conventions that enforcement of data integrity should be done in the application, not in the database.
To keep data integer on application-level, you can use model validations to enforce the presence of associations.
You have to add foreign keys to migration file to make your associations work correctly. With reference to the example mentioned, you have to add an attribute user_id to comments table. For more information on how Active Record Associations work, follow this rails guide.

Rails single table inheritance with lowercase type names

I'm working up an app that interfaces with a legacy database which has a type column used for single table inheritance. This database is still used by an existing PHP application so I have to work with what is there. I'm trying to set up some models for this and one of the key tables is set up with an STI scheme and a type column, however, all of the types in that column are entirely lowercase.
In my testing so far, rails works fine with the type column if I change the value to match the class name (for example, Claimant instead of claimant). However I don't want to go changing those values in the production database even though it would probably be ok, nor do I want to have to go in and modify the legacy app to save the names differently...
In order to fix this I have two questions...
1) Is there anyway I can configure the model to recognize that type = 'claimant' maps to class = 'Claimant'?
2) failing that, is there a way I can tell rails to not use STI on this table even though it has a type column?
I've done some googling and haven't come up with much yet...
I haven't tried this in an STI setting, but when using a legacy table I was able to use the method "set_table_name" on the ActiveRecord model.
class Claimant < ActiveRecord::Base
set_table_name 'claimant'
end
Or with a custom method:
def table_name
'claimant'
end
Apologies I haven't got an STI table handy to test this on, but thought it might help solve your problem.
In answer to the second part of your question, I believe you can disable Rails looking at the type column, by just specifying a non-existant column name.
class Claimant < ActiveRecord::Base
inheritance_column = :_type_column_disabled
end

What's the point of having foreign keys if Rails can access other model's attributes through associations anyways?

I'm a Rails beginner (and loving it so far). I'm not sure if this is a stupid question.
As far as I know, a foreign key, for example, like this: user_id in a model called Micropost will associate a micropost with the ID of an User model. Like this:
railtutorial.org
So you can do this: <%= micropost.user_id %> to get the ID of the user who created a micropost.
But can also do this: <%= micropost.user.id %> due to Rails' ability to associate models via has_many and belongs_to.
So I wonder, why are foreign keys necessary in Rails applications if the web framework can access other model's attributes through associations anyways?
Is it necessary to index them and improve database performance?
Or are they necessary so that something like this: micropost.user.username can work?
Foreign keys are used under the hood to make Rails associations work, and those associations wouldn't work without them. You can see this by attaching .to_sql to a Relation, e.g.:
> Blog.first.articles.to_sql
=> "SELECT `articles`.* FROM `articles` WHERE `articles`.`blog_id` = 42"
In this case it's using the blog_id foreign key to query the articles association.
It isn't necessary to index foreign keys, but it is a good idea and gives better performance.
So I wonder, why are foreign keys necessary in Rails applications if the web framework can access other model's attributes through associations anyways?
Foreign keys (along with the Primary key counter part) are what links the models together. If you did not have a user_id how would you know which user it ultimately is associated to?
Is it necessary to index them and improve database performance?
I find this practice helpful, in regards to performance.
Or are they necessary so that something like this: micropost.user.username can work?
It's only necessary in the context that to find micropost's associated user you need to know which user it is.
The key thing to understand about user vs user_id in your model is that user_id is the foreign key and that user is an instance of a User (eg, it's the model object).
Without user_id, rails can't make the correct user for you.
Note that if you are not preloading your associations, if all you need is the user id (say, for a building a URL), using micropost.user_id will be faster than micropost.user.id because rails won't need to instantiate the User object just to retrieve the id.
By calling micropost.user_id, Rails gives you the entry of the user_id column of the microposts table.
By calling micropost.user.id, Rails takes the user_id column from micropost and "searches" for Users with the corresponding id. When you do not have the user_id, Rails do not know anything about the correlation between the two tables.

Creating a new entry in a table that's not part of my rails project

I have a database that's pre-populated with tables from another project..
How do I access these tables with a rails project and create new entries in them?
Thanks!
If those tables are in the same database as your Rails project, then if they have id column as a primary key (or any other primary key that is integer type) you can just create model for each table and it should work. Of course you need to set_table_name and set_primary_key name.
With this, you should be able to:
MyModel.all
MyModel.build ...
and so on.

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