RAILS 3 model validation inclusion in does not work - ruby-on-rails

# ==Schema Information
# Schema version:
# Table name: terms
# id :integer not null, primary key
...
# user_id :integer
# term_type :string(255)`
term.rb:
class Term < ActiveRecord::Base
validates :term_type, :inclusion => { :in => %w(Term Segment Entity Abbreviation) }`
Rails 3.0.3, ruby 1.8.7, Windows via Cygwin
The validation does not seem to work, i.e. it accepts any value for term_type.
When using inclusion (or validates_inclusion_of which produces the same fail condition) do I need DB validations matching those in the model?
Any issues with Strings I should be wary of?
Term_type is just a string in the DB and not a separate table.
Any pointers much appreciated.
Vince

Have you tried using
validates :field, :inclusion => %{abc ade aeee}

Related

Ruby on Rails validation by pair of properties

I need to do validation on my model on Ruby on Rails.
I have model with 2 fields:
user_id
some_item_id
And I have many rows in DB with the same user_id, but with different some_item_id. And I need avoid duplication of this some_item_id towards to specific user_id.
In Rails exist some 'magic' validation in one line for this?
validates : user_id, :presence => true, :uniqueness => { :scope => : some_item_id }

How to restrict values for a column

I want to restrict available values for a field. So the value of the column must be from specified set of values. Is it possible using migration/models? Or I have to do it manually in my DB?
You'll use validations for this. There's a whole Rails guide on the topic. The specific helper you're looking for in this case is :inclusion, e.g.:
class Person < ActiveRecord::Base
validates :relationship_status,
:inclusion => { :in => [ 'Single', 'Married', 'Divorced', 'Other' ],
:message => "%{value} is not a valid relationship status" }
end
Edit Aug. 2015: As of Rails 4.1, you can use the enum class method for this. It requires that your column be an integer type:
class Person < ActiveRecord::Base
enum relationship_status: [ :single, :married, :divorced, :other ]
end
It automatically defines some handy methods for you, too:
p = Person.new(relationship_status: :married)
p.married? # => true
p.single? # => false
p.single!
p.single? # => true
You can read the documentation for enum here: http://api.rubyonrails.org/v4.1.0/classes/ActiveRecord/Enum.html
It depends on the amount of confidence you need. You could just add a validator to your model to restrict it to those values but then you wont be sure that existing data will match (and will cause subsequent saves to fail because of validation) and also that other changes could be made by other apps/raw sql that would get around it.
If you want absolute confidence, use the database.
Here's what you might want to use if you do it in the database (which is quite limited compared to what a rails validator could do: http://www.w3schools.com/sql/sql_check.asp

update_attributes doesn't take a role

I have a model with two attr_accessible lines
attr_accessible ...., :as => :user
attr_accessible ...., :as => :admin
Then in my controller I do this
if #user.update_attributes(params[:user],:as => :user)
And I get wrong number of parameters 2 for 1, however: #user.assign_atrributes(params[:user],:as => :user) works.
I am using mongoid. Any ideas?
I think you found something that has not been implemented yet in your version of Mongoid -- but please check a later Mongoid version, where it seems to be implemented since 2.2.1!
The doc says that :as is a valid option in Mongoid::Document
http://mongoid.org/docs/documents/access.html (see bottom of page)
But it says: You can scope the mass assignment by role by providing the role as an option to the constructor or create methods.
It doesn't speak of update_attributes in particular - update_attributes is not a constructor
Checking in the source code reveals that it's not implemented in update_attributes() in Mongoid versions < 2.2.1 , but later versions have it implemented!
If you're using a later version of Mongoid, and still experience problems,
I would recommend to post this on the Google Mongoid Group as a bug, mentioning your Mongoid version number.
See also:
http://groups.google.com/group/mongoid/
EDIT:
Looks like it's a missing feature in Mongoid 2.1.7
in the mongoid source code, update_attributes() calles write_attributes(), which does not know about the option :as
but if you look at the source code of Mongoid 2.3.1 , you'll see that it's implemented there since 2.2.1!
write_attributes() calls assign_attributes , which honors the option :as
# Allows you to set all the attributes for a particular mass-assignment security role
# by passing in a hash of attributes with keys matching the attribute names
# (which again matches the column names) and the role name using the :as option.
# To bypass mass-assignment security you can use the :without_protection => true option.
#
# #example Assign the attributes.
# person.assign_attributes(:title => "Mr.")
#
# #example Assign the attributes (with a role).
# person.assign_attributes({ :title => "Mr." }, :as => :admin)
#
# #param [ Hash ] attrs The new attributes to set.
# #param [ Hash ] options Supported options: :without_protection, :as
#
# #since 2.2.1
def assign_attributes(attrs = nil, options = {})
_assigning do
process(attrs, options[:as] || :default, !options[:without_protection]) do |document|
document.identify if new? && id.blank?
end
end
end
You can find the source code this way:
$ find ~/.rvm/gems/ruby-1.9.2-p0/gems/mongoid-2.1.7/lib/ -type f -exec grep -l 'def write_attributes' {} \;
~/.rvm/gems/ruby-1.9.2-p0/gems/mongoid-2.1.7/lib/mongoid/attributes.rb
$ emacs ~/.rvm/gems/ruby-1.9.2-p0/gems/mongoid-2.1.7/lib/mongoid/attributes.rb

Rails validation context

I need help with my ActiveRecord model. I have context based validations (mis)using the build-in context options for validations:
validates :foo, :on => :bar, :presence => true
model = Model.new
model.foo = nil
model.valid? # => true
model.save # works as expected
model.valid?(:bar) # => false
model.save(:context => :bar) # fails and returns false
But using my model in a accepts_nested_attributes_for :model and calling parent.save fails (the validation gets called and returns false), any suggestions or solutions?
Still no answer? To explain more about my problem: I have a model called Form which has many Fields. Users should see validation errors on submit, but the form should be saved anyway (with and without errors). There are different types of Fields, each with global validations (to ensure database consistency) and its own specific user-defined validations (to validate user-entered data). So my Fields look someway like that:
# Global validations, to ensure database consistency
# If this validations fail, the record should not be saved!
validates_associated :form, :on => :global
...
# Specific user-defined validations
# If this validations fail, the record should be saved but marked as invalid. (Which is done by a before_save filter btw.)
def validate
validations.each do |validation| # Array of `ActiveModel::Validations`, defined by the user and stored in a hash in the database
validation.new(:on => :specific).validate(self)
end
end
In my controller:
# def create
# ...
form.attributes = params[:form]
form.save!(:global)
form.save(:specific)
Is something similar possible in Rails using the built-in functionality? Btw this not my actual code, which is quite complicated. But I hope, you guys will get the idea.
Try conditional validations
class Customer
attr_accessor :managing
validates_presence_of :first_name
validates_presence_of :last_name
with_options :unless => :managing do |o|
o.validates_inclusion_of :city, :in=> ["San Diego","Rochester"]
o.validates_length_of :biography, :minimum => 100
end
end
#customer.managing = true
#customer.attributes = params[:customer]
#customer.save
"Ability to specify multiple contexts when defining a validation" was introduced in Rails 4.1 - check validate method, :on options description
Only for Rails 5+:
You are looking for
with_options on: :custom_event do
validates :foo, presence: true
validates :baz, inclusion: { in: ['b', 'c'] }
end
To validate or save use
model = YourModel.new
# Either
model.valid?(:custom_event)
# Or
model.save(context: :custom_event)
Change has_nested_attributes_for :model to accepts_nested_attributes_for :models.
Hope this helps.
Good luck.

MongoMapper and Rails 3 results in undefined method 'timestamps!'

I'm getting the error "undefined method 'timestamps!' when using Rails 3 with MongoMapper and was wondering if anyone can help resolve this problem.
I'm using Rails 3.0.1, mongo_mapper 0.8.6, and mongo 1.1
My model:
class User
include MongoMapper::EmbeddedDocument
key :_id, String
key :name, String, :required => true, :limit => 100
key :email, String, :required => false, :limit => 200
key :bio, String, :required => false, :limit => 300
timestamps!
end
First off, I'll note that if you're using Rails 3, you might want to look at Mongoid. It uses ActiveModel so you get all the Rails 3 polish with it. I prefer MongoMapper for 2.3.x projects, but Mongoid has seemed much more stable for me in Rails 3 projects.
That said, the timestamps! method is provided by the Timestamps plugin, which should be loaded as a part of the MongoMapper::Document inclusion. However, you could try including it manually:
class User
include MongoMapper::Document
plugin MongoMapper::Plugins::Timestamps
timestamps!
end
If the timestamps module isn't being loaded for any reason, that should manually include it in your model, and should make it available for use.

Resources