Model named "Type" in Rails - ruby-on-rails

Good Day.
I have a problem with my Model named "Type". The error is:
undefined method `all' for ActiveRecord::AttributeMethods::Serialization::Type:Class
In this particular part of validation:
validates :type_id, presence: { message: 'selected is invalid' }, inclusion: { in: 1..Type.all.count }
Maybe it's due to reserved names conflict in Rails. But is there a way that Rails will consider this name before I proceed to refactor? (if nothing else to do).
It's really a bad choice for a name but it's too late.
PS.
When I do 'Type.all.count' in rails console, there are no errors that occured.

Here is a list of reserved words in Rails. As you can see, type has also been reported to cause problems.
Rails is built over convention over configuration agreement, so I would suggest just to pick another model name (which is not mentioned in stated blog post).
Take a look at this thread to get an idea of what should be done to turn your Type model to something else.
In case you are completely sure model name is not the case, you could try to trick around with different validation notations like
inclusion: { in: 1.upto(Type.all.count).to_a}

Ruby's constant lookup is resulting in it finding the "wrong" Type class. Using "::Type" forces ruby to use the top level Type constant.
You should note that this count will be done once only: when the rails instance starts. If new types were to be added, the validation would not take that into account. If a type were ever deleted then it would not allow the last type to be used.
If you have a type association then you could do
validates_presence_of :type
Upon saving it would try and load the corresponding Type object from the database, so saving would fail if there was no such row.
For a really strong guarantee, you could use a foreign key constraint (the foreigner gem adds helpers to rails migrations for this, but you can also just write the sql statement by hand)

Fortunately, I found a workaround. However, it is not recommended but if you don't want to do Migration and ton's of Refractions, here is my solution (credits to twonegatives).
in my validation code:
inclusion: { in: 1.upto(:type_alias) }
then create that method type_alias
def type_alias
Type.all.count
end

Related

How to access translation key for ActiveModel validation error?

I Have a situation, where I wan't to store the translation key for a validation error in my db instead of the error message it self. Imagine the following situation:
class Car < ActiveRecord::Base
validates_presence_of :year, :fuel
end
car = Car.new(:fuel => 'Diesel')
car.save!
#=> ActiveRecord::RecordInvalid
Now if I call:
car.errors
#=> :year=>["can't be blank"]
I get the translated error message.
Instead I would like to extract the translation key that would generate this (in this case I think it would be something like errors.messages.blank), so I can store it in my database in a different model e.g. FailedCar so I can later on generate an I18n customized form for filling in the missing information manually in a view.
UPDATE
I think it's this method that I need to hook into. I want to fetch the key and the options returned, so I can perform the translations again at a later point in time.
Okay I finally got it!
The solution is NOT to patch or do anything on the rails side of things - instead - the answer lies in the I18n gem.
I18n, which rails uses for translations by standard, has the ability to plugin new backends to provide more flexibility to it. In this case, the backend called metadata does exactly what I needed. When adding I18n::Backend::Simple.include(I18n::Backend::Metadata) to an initializer, it gives me the possibility of extracting all translation related information directly from the error message string by adding the method call translation_metadata.
A fantastic simple solution to a complicated problem :-)
Have you looked at (.yml) local files too? You can store it as a translation string. For more Info Rails Internationalization.

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.

Problem with validates_uniqueness_of

I'm using rails 2.3.5 and Authlogic in our website, and I have been getting errors on the database through hoptoad of users with duplicated emails trying to be saved. The problem is, obviously I have the validates_uniqueness_of :email on the model.
On my tests here in development I get the expected validation error and the user is not saved, but in production, I keep getting this errors on the DB layer.
I've tested with case sensitive emails and it also validated correctly.
I've checked and the class and there is no attr_accessor or any other attribute override, and I don't think Authlogic would do it in a wrong way...
What could be happening in production? Are there any cases where rails validates doesn't work?
Locate the SQL running validates_uniqueness_of in your development log, and if you see something like WHERE (email = BINARY 'foo#example.com'), try creating a user with FOO#EXAMPLE.COM and now you can reproduce the DB-level duplicate exception.
To fix this, put the following code in config/initializers/patches.rb:
class ActiveRecord::ConnectionAdapters::Mysql2Adapter
def case_sensitive_equality_operator
"="
end
end
Note that Mysql2Adapter should be MysqlAdapter if you're on Rails 2.
On a side note, it is a longstanding bug in Rails IMO - handling case-sensitivity in Ruby level doesn't make sense at all. If you need case-sensitive lookup, you should have the column collation of utf8_bin. If you need case-insensitive lookup, you should have the column collation of utf8_general_ci. Applying BINARY function in the where clause will disable the use of index, and validates_uniqueness_of causes full table scan every time you try to create/update a record. If you have millions of records, you're totally screwed. The patch above will fix that, too - in fact, it was my original motivation to create that patch.
If you agree, please +1 to https://github.com/rails/rails/issues/1399 :)
Have you tried recreating the scenario. Why should throw errors that warrant Hoptoad Notification. I mean, basically if you have a it should not save the user and not throw an error for hoptoad to notify you about.
Also with authlogic, i don't think you are required to specify the validate_uniqueness_of for email. Usually authlogic will take care of that for you.
So I guess, its time for you to deep dive.
Look at the logs, and try recreating this error locally. Its always best to retrace the steps leading to error.
More details, error stack , code would definitely be helpful.
Just a guess but could it be that your email column allows null, validates_uniqueness_of is ignoring nil (or blank) values and that your users are trying to register without specifying their email addresses?

Cannot skip validation in Rails 3?

I'm working on a project in Rails 3 where I need to create an empty record, save it to the database without validation (because it's empty), and then allow the users to edit this record in order to complete it, and validate from then on out.
Now I've run into a pretty basic problem: I can't seem to save a model without validating it under any circumstances.
I've tried the following in the console:
model = Model.new
model.save(false) # Returns RuntimeError: Called id for nil, which would mistakenly be 4 -- if you really wanted the id of nil, use object_id
model.save( :validate => false ) # Returns same error as above
model = Model.create
model.save(false) # Same runtime error
model.save( :validate => false ) # Same runtime error
I then tried changing all the validations in the model to :on => :update. Same error messages on any attempt to save.
So what am I missing here? How can I create an empty record and then let validation occur as the user edits it?
Thanks!
It is a bad practice to have invalid models saved by normal use cases. Use conditional validations instead:
validates_presence_of :title, :unless => :in_first_stage?
or if you have many:
with_options :unless => :in_first_stage? do
validates_presence_of :title
validates_presence_of :author
end
This way nothing stands in way to have nightly integrity tests, which checks all records for validity.
A valid use case for saving without validations would be for testing edge cases, e.g. to test that a database constraint is enforced.
*sigh...*
Found the problem... one of my after_validate method calls was adding information and resaving the model, hence the errors I was getting weren't from the console input, they were coming from the after_validate method which was saving again.
Thanks all.
For emergencies only
Assuming that you have considered this very carefully and are certain that this is a good idea, you can save without validation using:
my_model.save validate: false
There are almost no valid use cases for this, and it should be considered an emergency one off procedure. Your use case does not qualify.
Problems with invalid records
Having invalid records in the database leads to all manner of problems down the line. For example, you send an email to all users and update a 'last_contacted_at' field on your user model. Your invalid users will not be updated and will descend into an email spiral of death.
Conditional validation
As other posters have pointed out, conditional validation will solve most issues for which you might otherwise have used validate: false.
Instead of placing an invalid model in the database, store the partially completed model (created with Model.new) in a session. Only save it to the database when it is completely valid.

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)

Resources