What's the point of migration column options? - ruby-on-rails

I'm trying to understand why Rails chooses to include :limit, :null, :default and others in its migrations column options.
It's my understanding that Rails is opinionated against DB constraints, rather enforcing consistency and non-nullness (and many others) through ActiveRecord validations such as validates_presence_of and various callbacks such as before_save.
Assuming hypothetically that I fully subscribe to the "everything in the model" philosophy, shouldn't I avoid using those abovementioned column options? What am I missing here?
Thanks!

Default values are useful to set at a db level, otherwise you're going to have code everywhere to ensure booleans are set to false by default instead of nil.

Related

Implications of Having an object_id Column in Rails

What are the implications of having a object_id / object_type on a model (for a polymorphic association) in regards to Object itself containing an object_id and that overriding it (http://ruby-doc.org/core-2.3.1/Object.html#method-i-object_id)?
class Event
belongs_to :object, polymorphic: true # object_id/object_type
end
When I search for object_id through the whole codebase of one of my rails projects (including all gems), I can see over 200 hits. In Rails only, this is about 50 hits.
I'd expect problems with records comparison, using them as hash keys, putting them to sets, perhaps also duplicating them with dup. In Rails, record.object_id is referenced in caching, has_many_through associations, AREL, pretty printing the record, minitest expectations, also in pry debugger,
But just from quick-looking trough the code it is very hard to guess if it will cause problems or not and I generally tend to be very defensive about such potential problems - you'll never know for sure if your next usage of the object will not break things in a way that is both very hard to debug and perhaps impossible to fix.
As I said above, I'd be very curious if you tried, but myself would rather name it belongs_to :thing, polymorphic: true or better yet something even more specific.
If you attempt to define object_id on a class you'll find that you get the following angry warning from the Ruby interpreter warning: redefining 'object_id' may cause serious problems (try it from IRB). That sounds scary - and the incidents may be tied to specific versions of Ruby (and vary based on the version used). I'd recommend fixing this.
I believe you can belong_to object, while defining the foreign_key to something else, like foreign_key: :object_identifier. That way you dont have to worry about object_id.
I think the best to follow this documentation Active Record Associations, I think defining another object_id will make you sustain the relation manually in your code and you will lose Active Record features for doing that.

What is the Rails Convention for validating field length?

With ActiveRecord models, I know you can validate the length of an input field like so
class User
validates :user_name, length: { maximum: 20 }
end
However, one of the design patterns in Rails recommends thin models. If you have a ton of validations, the above code might seem intimidating. I read there was another way you could do this.
You can simply use an ActiveRecord::Schema to accomplish the same task.
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :user_name, limit: 20
end
end
end
That accomplishes the exact same thing only you don't even need the second line in your Users model.
What is the standard Rails convention regarding this?
Some people would argue that you have to have skinny controllers and skinny models. However, this can create several additional classes in your application.
Sometimes having a fat model if documented and laid out logically can be easier to read. I will ignore the 'best practices' if it makes the code easier to read as I may not always be the only person touching that code. If the application scales to a point where multiple people will be accessing the same files, I will consider extracting it at that point as a refactor. However, this has rarely been the case.
While it is good to set limits on your database, you also want to have client validations to prevent someone having their data truncated with no feedback to them. For example, (a really horrible example), if you were to limit the username of an User to only six characters and I type in kobaltz as my username, I will wonder why my username/password never works as the database truncated it to kobalt. You will also run into issues where MySQL (or similar) will throw database level errors which is annoying to fix/troubleshoot. You also have to consider if modifying a database in production, if you set the limits where they did not exist before, you could end up corrupting your data.
Having a few validations in your model does not make it a 'fat' model in my opinion. It makes it easier to read. If you're not using an IDE like RubyMine and only using an editor, you do not have the luxury of Jump to Definition which can make the abstraction of your model easier to follow.
If you use second approach, you won't be able to get the error. Its on mysql level and not on model level, so active record won't tell you the reason for user not getting created or updated.
object.errors
will be empty.
Check this
http://apidock.com/rails/ActiveModel/Errors/full_messages

Why would someone use the gem foreigner?

This is most likely a noob question since people use this gem and a lot of people love it, but I don't get the purpose. I'm looking at a project and its been used here many times in places such as t.references :foreign_key_table_name , :foreign_key => true, add_foreign_key :table :foreign_key_table_name, :options, and in a create t.foreign_key :foreign_key_table_name. Hope those weren't confusing since they're out of context.
But I don't get how this is different from what rails does built in with t.references :foreign_key_table_name or from me just adding t.integer :foreign_key_table_name_id? does it simply make it more readable by making clear that this is a 'foreign key'? I could just add a comment instead of a gem if thats the case... The only advantage I see is that you can move options such as :dependent into the migration instead of having it in the model, but who cares?
Some database engines support legit foreign key constraints: if someone tries to save a Child with a parent_id of 5, but there's no Parent with id 5, then the database itself (not Rails) will reject the record if there's a foreign key constraint linking children.parent_id and parents.id.
A foreign key can also specify what happens if the parent is deleted: in MySQL, for example, we can delete or nullify the dependent records, like how Rails does with :dependent, or even just straight-up reject the deletion and throw an error instead.
Since not all database engines offer this functionality, Rails offers to emulate it with :dependent, and it's nice to have it on the software level so that dependent child records can fire their destroy callbacks when the parent is deleted. Since the feature is engine-independent and therefore pretty much schema-independent, Rails doesn't handle the creation/deletion of foreign keys. That's where foreigner comes in: if your engine supports foreign key constraints, and you want that extra confident in your data integrity, foreigner can help with that.
Resurrecting an old question here, but…
Having rails enforce the relationship is fine, within rails itself.
However, if your project grows to have code that also accesses these tables from other languages, that will not have the benefit of rails enforcing the relations. These foreign key constraints are baked into the SQL tables themselves, so can protect non-rails code.
This will also protect you if you need to perform datafixes or otherwise manipulate your data via native SQL.
Another reason is that some documentation tools for SQL look at foreign keys on the DB, so it is cool to have a gem that generates them. Rails 4 added the ability to define foreign keys in the same migration that creates the table with:
t.references :something, foreign_key: true
And the generators will do this for you if you use the references type. Rails adds an index on something_id by default when using foreign_key like this

Rails Association Validations: The field, or the _id field?

One of the messier practices I have in Rails development is juggling validations of associated fields between validating the actual object (eg: validates_presence_of :related_object) and validating on the id column for that association (eg: validates_presence_of :related_object_id).
I figure I should probably start being a little more consistent with this, and before I commit to anything, I'm wondering if there's any advantage of either method over the other? I can't think of anything, but then I've been known to overlook stuff before. So, does it make any difference? Is there a convention re: what most developers do that I should abide by?
Any suggestions appreciated.
This question comes up every so often.
In most cases you will want to validate the presence of the actual associated object, not just verify that an id (which could well be invalid) has been set.
Validating association_id will also prevent you from creating the object with a new association record and saving both together.
Of course you have to check the presence of :object_id. If you check the presence of :object then this object will be fetched from your DB and then will be checked via simple blank?. I guess you won't be happy with additional DB hit.

ActiveRecord without setting up database tables? (declarative like Django)

In Django, you fully describe your models in models.py. In Rails with ActiveRecord, you describe part of a model in in the /models directory, and part of it in migrations. Then ActiveRecord introspects model properties from the existing database tables.
But I find migrations, columns, and tables to be a headache.
How can I do like Django -- just declare all model properties instead of introspecting them from the database tables?
And for extra credit, explain where and why this would be a bad idea. :)
If you hate on Migrations, try going NoSQL. No migrations!
So you'd just add properties to your document when you need them. In your code, handle the fact that they may not exist and bam!
I took the following model definition (notice you don't inherit form activerecord) from a blog about tekpub Also recommend the Herding Code podcast
class Production
include MongoMapper::Document
key :title, String, :required => true
key :slug, String, :unique => true, :required => true, :index => true
key :description, String
key :notes, String
key :price, BigDecimal, :numeric => true
key :released_at, Date, :default => Date.today
key :default_height, String, :default => '600'
key :default_width, String, :default => '1000'
key :quotes, String
#royalty info
key :producers, String
timestamps!
end
Try the auto_migrations plugin. I don't think it's a bad idea for development, but I would switch to migrations after going to production when there is critical data in the database.
You may also be interested in replacing ActiveRecord with DataMapper, which works in Rails 3. It has the style you are talking about, with the description of the data fields of a model in the model code instead of a separate database schema file.
I think DataMapper is what you are asking for. Once set up, you'd either use DataMapper.auto_migrate! or DataMapper.auto_upgrade!. The former will drop tables if they exists before creating them, thus destroying any data. That would be bad for production. The latter is how you avoid losing data, and should be just fine for production.
Without knowing exactly what its doing, I'd guess it's inspecting tables during startup to determine whether to make database changes. That can drag down start up time, especially with a lot of models/tables. Which is actually one of the good reasons to consider NoSQL - specifically Mongo as mentioned above. It's fast. Really fast, and thus the start up cost is much, much less. MongoMapper is the way to go. The tekpub blog post is a must read.
I first heard about DataMapper in reading about Merb, so it makes sense that it's in rails 3. I don't know whether you may be able to get it working in rails 2.x.

Resources