I have a validation that looks like this:
class Book < ActiveRecord::Base
belongs_to :author
validates :name, uniqueness: { scope: :author_id }
end
The problem is that I want to allow duplicate names where the author id is nil. Is there a way to do this using the validates method (and not a custom validation)?
Yes, with a Proc and :unless on the validator.
class Book < ActiveRecord::Base
belongs_to :author
validates :name, uniqueness: { scope: :author_id }, unless: Proc.new { |b| b.author_id.blank? }
end
Recommended Reading: http://guides.rubyonrails.org/active_record_validations.html#using-a-proc-with-if-and-unless
Make it conditional:
validates :name, uniqueness: { scope: :author_id }, if: :author_id?
Related
I working on a Rails application, currently we structure the app by modules. Right now we have 2 separate model for users: User and Freight::Customer::User.
I have a new model Freight::Customer::MembershipStatus looks like this:
class Freight::Customer::MembershipStatus < ActiveRecord::Base
belongs_to :customer, class_name: 'Freight::Customer'
belongs_to :created_by, class_name: 'User'
validates :from, presence: true
validates :to, presence: true
validates :customer, presence: true
validates :status, presence: true
end
In this case, the created_by is reference to User. But when the code run membership_status.created_by, rails try to look for the Freight::Customer::User, I think it because Rails try to look for model within the same module first.
Is there a way to config this model to use the outer User model class?
You can get user class using this type, try this.
class Freight::Customer::MembershipStatus < ActiveRecord::Base
belongs_to :customer, class_name: 'Freight::Customer'
belongs_to :created_by, class_name: '::User'
validates :from, presence: true
validates :to, presence: true
validates :customer, presence: true
validates :status, presence: true
end
I have two ActiveRecords Author and Book.
class Author < ActiveRecord::Base
has_many :books
enum author_type: {
musician: 0,
scientist: 1
}
accepts_nested_attributes_for :books
end
class Book < ActiveRecord::Base
belongs_to :author
validates :name, presence: true
validates :score_url, presence: true
end
Now Book validates presence for both name and score_url,
but I want skip validation for score_url when author.author_type is scientist.
I tried this way, but author can not be found during creation.
class Book < ActiveRecord::Base
belongs_to :author
validates :name, presence: true
validates :score_url, presence: true, if: "author.scientist?"
end
What is the best solution here?
You need to provide a Proc to the conditional validation
validates :score_url, presence: true, if: Proc.new { |book| book.author.scientist? }
if your validation gets any more complex, you should extract the logic to a new method.
validates :score_url, presence: true, if: :author_scientist?
private
def author_scientist?
author.present? && author.scientist?
end
I have a nested recourse called "transactions" inside another recourse "budgets".
All I'm trying to accomplish is for my users to be able to edit individual "transactions". However when I go to /1/transactions/1/edit I get a LocalJumpError saying "no block given (yield)".
There might be a very simple solution to this but I haven't been able to find it yet.
routes.rb:
resources :budgets, :path => '/' do
resources :transactions
end
budget.rb:
class Budget < ActiveRecord::Base
belongs_to :user
has_many :transactions
validates :amount, presence: true
validates :title, presence: true
validates :user, presence: true
validates :amount, numericality: true
extend FriendlyId
friendly_id :title, use: :slugged
def should_generate_new_friendly_id?
new_record?
end
end
transaction.rb
class Transaction < ActiveRecord::Base
belongs_to :user
belongs_to :budget
validates :amount, presence: true
validates :user, presence: true
validates :budget, presence: true
validates :date, presence: true
validates :amount, numericality: true
validates :is_positive, :inclusion => {:in => [true, false]}
end
transactions_controller.rb
def edit
#budget = Budget.friendly.find(params[:budget_id])
#transaction = #budget.transaction
end
And in the view transactions/edit.html.erb:
<%= form_for(#transaction) do |f| %>
What am I missing?
Naming a model Transaction conflicts with ActiveRecord::Transactions. You'll need to rename your model.
http://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html
I have an Album model and Track model. I want to make sure that the name of each track on the album they belong to are unique. I tried using this validation in my Track model
validates :name, presence: true, uniqueness: true, scope: :album_id
but get the error: Unknown validator: 'ScopeValidator'
What am I doing wrong?
class Album < ActiveRecord::Base
has_many :tracks
accepts_nested_attributes_for :tracks, :reject_if => :all_blank, :allow_destroy => true
validates :name, presence: true, uniqueness: true
end
class Track < ActiveRecord::Base
belongs_to :album
validates :name, presence: true, uniqueness: true, scope: :album_id
end
You need to scope the uniqueness, not put it as a separate argument.
class Track < ActiveRecord::Base
belongs_to :album
validates :name, presence: true, uniqueness: { scope: :album_id }
end
class Category < ActiveRecord::Base
belongs_to :user
belongs_to :group
validates :name, presence: true
validates :user_id, presence: true
validates_presence_of :group
.
.
.
I only want to validate the presence of group if group_id is not nil. Is this possible? Or do I need to write a new validates method?
You can use inline if for this
validates :group, :presence: true, if: "group_id.present?"
You can use a Proc to conditionally execute your validation. See the Rails Guide for more.
validates_presence_of :group, unless: Proc.new { |category| category.group_id.nil? }