I have to models: Tag and TagNumeric each one with a category field
I shouldn't be able to create Tags of different types with the same category. How can I validate this?
EDIT:
I forgot to mention
TagNumeric < Tag
class Tag
include Mongoid::Document
validates_presence_of :type, :value
field :category, type: String
field :value, type: String
field :color, type: String
validates :value, :presence => true, :uniqueness => {:scope => :category}
class TagNumeric < Tag
field :value, type: Integer
it 'its category should be unique within the Tag class type' do
Tag.create(category: 'Movie', value: 'Avatar')
TagNumeric.create(category: 'Movie', value: 'Iron man').should_not be_valid
end
If anybody is having the same problem here is how I solved it
validate :uniqueness_within_category
def uniqueness_within_category
first_category_type = (Tag.find_by(category: self.category).nil?)? 'none' : Tag.find_by(category: self.category)._type
if first_category_type == 'none'
#It doesnt exist then should be allowed
return
end
#If it exists within another class type then shouldnt be allowed
if self._type != first_category_type
errors.add(:category, 'Must be unique within tag type')
end
end
Testing started at 6:22 PM ...
1 examples, 0 failures, 1 passed
Related
I have two models Item and Tag
class Item
include Mongoid::Document
field :title, type: String
has_many :tags
validates_length_of :tags, minimum: 1
end
class Tag
include Mongoid::Document
field :title, type: String
belongs_to :item
end
The Item must have minimum 1 tag.
When item is created validation works very well:
item = Item.create(title: "black hole")
item.tags << Tag.create(title: "black")
item.tags << Tag.create(title: "heavy")
puts item.valid? # => true
item.save
But validation fails when the existed item is modified:
item = Item.find(item.id)
item.title = "nothing"
puts item.tags.count # => 2, it's ok
puts item.valid? # => false, it's wrong
How to validate count of related documents properly?
Have you tried adding attr_accessible to title?
It would look like this:
class Item
include Mongoid::Document
attr_accessible :title # <-- here
field :title, type: String
has_many :tags
validates_length_of :tags, minimum: 1
end
I am following this video http://railscasts.com/episodes/258-token-fields-revised and i implement this also sucessfully. But now i am using namespace.
I have lends_controller inside folder employee inside asset folder.
this is my model of lend controller
class Employee::Asset::Lend
include Mongoid::Document
include Mongoid::Timestamps
field :name, type: String
field :text, type: String
field :date
field :asset_tokens
field :user_id, type: String
has_and_belongs_to_many :assets
belongs_to :tags
def asset_tokens=(tokens)
self.asset_ids = Asset.ids_from_tokens(tokens)
end
end
Now i have another model asset. There i have to define has and belongs to this lend model also I did this
class Asset
include Mongoid::Document
field :name, type: String
field :description, type: String
field :serial_number, type: String
field :status, type: Integer
field :tag_tokens
field :quantity, type: Integer
validates_presence_of :name
validates :serial_number,:uniqueness => true
has_and_belongs_to_many :employee_asset_lends
has_and_belongs_to_many :tags
def self.tokens(query)
assets = where(name: /#{Regexp.escape(query)}/i)
end
form for lend controller is
<%= f.label :asset_tokens, "Assets" %>
<%= f.text_field :asset_tokens, data: {load: #employee_asset_lend.assets}%><br>
<%= f.input :date,:input_html => { :class => "dp1"},:label=> "Lend Date"%>
inside coffescript file for lend.js.coffee
jQuery ->
$('#employee_asset_lend_asset_tokens').tokenInput '/assets.json'
theme: 'facebook'
prePopulate: $('#employee_asset_lend_asset_tokens').data('load')
But it gives error uninitialized constant EmployeeAssetLend from asset views.
and from lend view it gives error like undefined methodall_of' for Employee::Asset:Module`
pleaes check the right way to make HABTM-has_and_belongs_to_many Assosiation for more details
I am using Rails 3 with mongoid 2. I have a mongoid class forum, which embeds_many topics.
Topics embeds_many forumposts
When I try to save a forumpost doing the following in my controller...
#forum = Forum.find(params[:forum_id])
#forum.topics.find(params[:topic_id]).forumposts.build(:topic_id => params[:forumpost][:topic_id], :content => params[:forumpost][:content], :user_id => current_user.id,:posted_at => Time.now, :created_at => Time.now, :updated_at => Time.now)
if #forum.save
On save I get...
undefined method `each' for 2012-11-14 23:15:39 UTC:Time
Why am I getting that error?
My forumpost class is as follows...
class Forumpost
include Mongoid::Document
include Mongoid::Timestamps
include Mongoid::Paranoia
field :content, type: String
field :topic_id, type: String
field :user_id, type: String
field :posted_at, type: DateTime
attr_accessible :content, :topic_id, :user_id, :posted_at, :created_at, :updated_at
validates :content, presence: true
validates :topic_id, presence: true
validates :user_id, presence: true
belongs_to :topic
belongs_to :user
end
There is alot wrong/wierd with your example code, so lets see if we can start at the start:
You say forum embeds many topics, which embeds many posts. But your model is using a belongs_to association. Belongs_to is used for references which are different than embedded documents. If your Topic model has this:
class Topic
...
embeds_many :forumposts
...
end
Then your Forumpost model should have this:
class Forumpost
...
embedded_in :topic
...
end
Read up on references vs embedded documents here: http://mongoid.org/en/mongoid/docs/relations.html
Next point, You don't need to put :topic_id into the forumpost since you are building it off the topic.
Next point, don't save the forum, save the forumpost. And instead of doing a build followed by a save, try just doing it as a create in one go.
Next point, instead of setting user_id => current_user.id, try setting user => current_user. This is the magic that the belongs_to association provides... its cleaner and avoids messing around with IDs.
Next point, why do you need both created_at (supplied by Mongoid::Timestamps) and posted_at ?
Last point, you shouldn't need to set the timestamps, they should be set automatically when created/updated (unless for some reason you actually need posted_at).
Try something more like this:
#forum = Forum.find(params[:forum_id])
#topic = #forum.topics.find(params[:topic_id])
if #topic.forumposts.create(:content => params[:forumpost][:content], :user => current_user)
#handle the success case
else
#handle the error case
end
I am new to Rails and Ruby. On my view, I have 2 radio buttons that ask if the person is a resident of the US. If they are, a state select is shown. If they aren't, a country select is shown.
I am trying to validate that a state was selected, if the person is a resident of the US.
How can I create a validation and access the state out of the addresses_attributes?
Here is my model:
class Person < ActiveRecord::Base
has_many :addresses, :as => :addressable
has_one :user
accepts_nested_attributes_for :user, :allow_destroy => true
accepts_nested_attributes_for :addresses
attr_accessor :resident
attr_accessible :campaign_id,
:first_name,
:last_name,
:user_attributes,
:addresses_attributes,
:resident
validates :first_name, :presence => true
validates :last_name, :presence => true
validates_presence_of :resident, :message => "must be selected"
end
These are the relevant parameters being sent:
"resident"=>"true",
"addresses_attributes"=>{"0"=>{"country_code"=>"",
"state"=>""}}
You need custom validation method.
validate :check_state_presence
def check_state_presence
if self.resident && !self.addresses.state.present?
self.errors[:base] << "You need to Select State if you are a US resident."
end
end
You can sort it out using validates_inclusion_of instead.
Ruby API says:
If you want to validate the presence of a boolean field (where the real values are true and >false), you will want to use validates_inclusion_of :field_name, :in => [true, false].
This is due to the way Object#blank? handles boolean values: false.blank? # => true.
+1 to #VelLes for the help in pointing me in the right direction. I am answering my own question because I had to change #VelLes example a bit to get it to work and I want other people to see the full solution.
Since I am using attr_accessor as a virtual attribute, when the true/false value comes in from the radio button, it gets stored as a string. Therefore if self.resident = "false", it will get evaluated to true.
You can do self.resident == 'false' or convert to a boolean and add a new self.resident? method. I chose the latter.
The boolean conversion came from this blog post, add to a file in config/initializers
class String
def to_bool
return true if self == true || self =~ (/(true|t|yes|y|1)$/i)
return false if self == false || self.blank? || self =~ (/(false|f|no|n|0)$/i)
raise ArgumentError.new("invalid value for Boolean: \"#{self}\"")
end
end
My final code is:
validate :check_state_presence
def resident?
resident.to_bool
end
def check_state_presence
if self.resident? && !self.addresses[0].state.present?
#the inline version of the error message
self.addresses[0].errors.add(:state, "must be selected")
end
end
Please let me know if there is a better 'rails' way to do this!
I trying to spec validations of my model this is my model
class Account < CouchRest::Model::Base
property :user, String
property :password, String
property :name, String
property :email, String
property :activate, TrueClass, :default => true
validates_presence_of :user, :password, :name, :email
validates_length_of :password, :in => 6..15, :if => lambda{|account| !account.password.blank? }
validates_uniqueness_of :user, :if => (lambda{|account| !account.user.blank?})
end
and into my model_spec i'm trying to do this
account = Account.new
account.should have(1).error_on_presence_of(:email)
But instead 1 error, I'm getting 6
I think that might be caused by validates of couchrest but not sure.
Can someone clarify this for me please?
P.S.: If I validate the same model into console I get 4 errors corresponding the four empty properties
It seems you're expecting 1 error, but there are actually 6. To figure out what is in the error hash, you can set a temporary expectation:
`account.errors.should == {}
Then the example will fail and RSpec will print the value of the error hash, and you can see which errors are actually being generated.