How to use MongoID validates_inclusion_of - ruby-on-rails-3

I have a model with a field that can contain a list of values. I want that list to be limited to a subset. I want to use validates_inclusion_of, but probably misunderstand that validation.
class Profile
include Mongoid::Document
field :foo, :type => Array
validates_inclusion_of :foo, in: %w[foo bar]
end
p = Profile.new
p.valid? #=> false; this is correct, as it should fail on empty lists.
p.foo = ["bar"]
p.valid? #=> false; this is incorrect. I would expect it to pass now.
p.errors #=> {:foo=>["is not included in the list"]}
What am I doing wrong? Can validates_inclusion_of be used for arrays?

Your field value is an array (field :foo, :type => Array)
Validation expects field to be not an array to check its inclusion.
By your example validation is checking for ['foo', 'bar'].include?(['bar']) # => false
So correct your :in option in validates_inclusion_of:
validates_inclusion_of :foo, in: [['foo'], ['bar']]

Related

rails length validation exception

It is possible have in model for example user model
class User < ActiveRecord::Base
attr_accessible :number
validates_length_of :number, :is => 4
...
end
validation on length 4 (1234) with one exception that number can be value 0 ? :-)
i was looking to documentation here http://api.rubyonrails.org/classes/ActiveModel/Validations/ClassMethods.html but i dont know how to do it ?
edit: now i realized that maybe regexp can be used, but thats not my strong field :-p
You probably want to allow length of zero to prepare for the case the input is nil or blank.
There is built-in simple solution for such case
validates :number, length { :is => 4 }, allow_blank: true
# allow_blank includes cases of both nil and blank
Done.
Doc: http://guides.rubyonrails.org/active_record_validations.html#allow-blank
If the number comes in as a string you can validate the format of it with a regex to achieve something close:
class User < ActiveRecord::Base
attr_accessible :number
validates :number, :format => { :with => /^(\d{4}|0{1})$/ }
...
end
This says to validate the format of the number (assuming it is a string) such that from the beginning of the string there is either a pattern of 4 digits or a single 0 digit followed by the end of the string.

Rails 3 Validation on Uniqueness - logic

Given the following invoice model:
validates :po_number, :invoice_number, :invoice_date, :date_received, :state_id, :division_id, :pending_state_id, :approver_username, :approver_email, :presence => true
validates :po_number, :uniqueness => {:scope => :invoice_number}
There are times when an invoice record is canceled (state_id = 4), but then needs to be re-created.
Can you help me with how to still validate uniqueness on po_number and invoice_number so the new record can be created even though the same combination exists with a different state_id if it was canceled?
Based on what you described, I believe it may be sufficient to include the :state_id in the scope and pass an :unless (or :if) option to exclude cancelled (or any other states) from the check:
validates :po_number, :uniqueness => {
:scope => [:invoice_number, :state_id],
:unless => :cancelled?
}
# assumes an instance method like
def cancelled?
state_id == 4
end
I think you'll need a custom validator. Something like this might work:
validate :unique_po_number
def unique_po_number
errors.add(:po_number, 'must be unique') if self.class.where('state != 4').where(:po_number => po_number).count > 0
end

How to filter IS NULL in ActiveAdmin?

I've a table with an integer column called "map_id", I want to add an activeadmin filter to filter if this column IS NULL or IS NOT NULL.
How could this be implemented ?
I tried the following filter
filter :map_id, :label => 'Assigned', :as => :select, :collection => {:true => nil, :false => ''}
But, I get the following error message :
undefined method `map_eq' for #
If anyone is happening on this thread belatedly, there is now an easy way to filter for null or non null in active admin :
filter :attribute_present, :as => :boolean
filter :attribute_blank, :as => :boolean
It is no longer necessary to add a custom method to the scope to accomplish this.
Not found a good solution but here is a how.
filters of Active_admin are accomplished by meta_search, you can override the functions automatically generated by meta_search in your model to get the behavior that you want, the best way is to use the scope since you need to return a relation in order to chain with other query/scopes, as stated here
in your model:
for :as=>:select filters, acitve_admin use the _eq wheres, here is the source code
scope :map_eq,
lambda{ |id|
if(id !='none')
where( :map_id=> id)
else
where( :map_id=> nil)
end
}
#re-define the search method:
search_method :map_eq, :type => :integer
in your ative_admin register block:
filter :map_id, :label => 'Assigned', :as => :select, :collection => [['none', 'none'], ['one', 1],['tow', 2]]
# not using :none=>nil because active_admin will igore your nil value so your self-defined scope will never get chained.
Hope this help.
seems search_method doesn't work in recent rails version, here is another solution:
add scope to your model:
scope :field_blank, -> { where "field is null" }
scope :field_not_blank, -> { where "field is not null" }
add to /app/admin/[YOUR MODEL]
scope :field_blank
scope :field_not_blank
you will see buttons for these scopes appear (in top section, under model name, not in filter section)
The new version of ActiveAdmin uses Ransacker. I manage to got it working this way:
On the admin
filter :non_nil_map_id, :label => 'Assigned', :as => :select, :collection => [['none', 'none'], ['one', 1],['tow', 2]]
For consistency, I took the same code from #Gret answer just changing the filter name
On your model
ransacker :not_nil_map_id, :formatter => proc {|id| map_id != 'none' ? id : 'none' } do |parent|
parent.table[:id]
end
This should trigger a search against nil in case the id is 'none', and active record will return all the nil id entries.
This thread helped a lot.
With ransackable scopes:
On the ActiveAdmin resource definition:
filter :map_id, :label => 'Assigned', as: :select, :collection => [['Is Null', 'none'], ['Not null', 'present']]
On your model:
scope :by_map_id, ->(id) { (id == 'none' ? where(map_id: nil) : where('map_id IS NOT NULL')) }
def self.ransackable_scopes(_auth_object = nil)
%i[by_map_id]
end

How can I get an ActiveRecord query to ignore nil conditions?

In order to avoid having to construct complicated dynamic SQL queries, I'd like to be able to just pass in nil values in my conditions, and have those ignored. Is that supported by ActiveRecord?
Here is an example.
event = Event.find(:all, :conditions => {
:title => params[:title],
:start_time => params[:start_time],
:end_time => params[:end_time]
}).first
In that particular case, if params[:start_time] is set to nil, ActiveRecord will search for those Events that have their start_time set to null. Instead, I'd like it to just ignore start_time. How do I do that?
You don't have to "create complicated dynamic SQL queries" to do what you need. Simply construct your conditions hash separately, and either exclude the null values at the time of creation or after you've created the hash.
conditions = {}
conditions[:title] = params[:title] unless params[:title].blank?
conditions[:start_time] = params[:start_time] unless params[:start_time].blank?
conditions[:end_time] = params[:end_time] unless params[:end_time].blank?
or
conditions = {:title => params[:title], :start_time => params[:start_time], :end_time => params[:end_time]}
conditions.delete_if {|k,v| v.blank? }
or
conditions = params.reject {|k,v| !([:title, :start_time, :end_time]).include?(k) }
but that last form will only work if the keys are actually symbols. In Rails the params hash is a HashWithIndifferentAccess which allows you to access the text keys as symbols. Of course you could just use the text values in your array of keys to include if necessary.
and then query with your pre-built conditions hash:
event = Event.find(:all, :conditions => conditions).first

Sphinx Scope Returning Nothing

I'm trying to create a simple scope that sphinx will index (Ruby on Rails). The normal scope returns what it should, the sphinx scope returns no results.
define_index do
# fields
indexes :name
indexes author
indexes description
indexes list_of_tags
indexes approved
# attributes
has created_at, updated_at, downloads
# delta indexing
set_property :delta => true
# weighting fields
set_property :field_weights => {
:name => 10,
list_of_tags => 6,
author => 5,
description => 4,
}
end
normal scope:
scope :approved, where(:approved => true)
sphinx scope:
sphinx_scope(:approval_scope) {
{:conditions => {:approved => "true"}}
}
Approved is a boolean field, however, since I'm indexing it as a field, I believe its value is treated as a String. Regardless, letting the value of the sphinx scope be "true" or true makes no difference - Theme.approval_score still returns 0 results unlike Theme.approval. I hope I'm missing something simple..
make the approved with has
define_index do
# fields
...
has approved
...
end
then
sphinx_scope(:approval_scope) {
{:with => {:approved => true}}
}