Rails Active Record Validation condition base - ruby

class Material < ActiveRecord::Base
belongs_to :material_type
belongs_to :product_review
validates :url, :presence => true, :if => :url_presence?
validates :video, :presence => true, :if => :video_presence?
def url_presence?
if !self.title.blank? and self.material_type.title.eql? :url
true
end
end
def video_presence?
if !self.title.blank? and self.material_type.title.eql? :video
true
end
end
has_attached_file :video,
:url => "/system/video/:id/:attachment/:style/:basename.:extension",
:path => ":rails_root/public/system/video/:id/:attachment/:style/:basename.:extension",
:default_url => "/image/video.png"
end
I assumption if its finds Title fields fill and material_type is url than it perform validation for url field presence validation check, but it not helpful

I think you need to compare strings, not symbols.
validates :url, :presence => true, :if => :url_present?
validates :video, :presence => true, :if => :video_present?
def url_present?
self.title.present? and self.material_type.title == "url"
end
def video_present?
self.title.present? and self.material_type.title == "video"
end

Related

Active admin nested form not working Error: too many arguments for format string

Following is my code block of state Model, SatatImage Model and Active Admin Code. In active admin when I try to create a new record or Edit a --record that time I show an error on production server. but works on my localhost in development mode,
---------Error---------------------------
too many arguments for format string
app/admin/state.rb:49:in `block (2 levels) in '
I am using Ruby 1.9, Rails 3,2, activeadmin (0.6.0)
======State Model===============
class State < ActiveRecord::Base
attr_accessible :name, :code
validates :code, :uniqueness => true
has_one :state_image, :dependent => :destroy
accepts_nested_attributes_for :state_image, :allow_destroy => true
.......
end
==============StatImage Model=============
class StateImage < ActiveRecord::Base
attr_accessible :state_id, :stateimage, :image_name
belongs_to :state
mount_uploader :stateimage, StateUploader
end
=======Active Admin part=================
ActiveAdmin.register State do
.....
form(html:{multipart:true}) do |f|
f.inputs "State Form" do
f.input :name, required:true
f.input :code, required:true
end
#line-49#
f.inputs "StateImage", for:[:state_image, f.object.state_image || StateImage.new] do |p|
p.input :stateimage, :as => :file, :label => "Image"
end
f.buttons :submit
end
end
I am using
f.semantic_fields_for
And Formtastic requires you to wrap ALL inputs in an "inputs" block. So this should be:
f.inputs 'State Image' do
f.semantic_fields_for :state_image, (f.object.state_image || StateImage.new) do |p|
p.inputs do
p.input :stateimage, :as => :file, :label => "Image"
p.input :_destroy, :as => :boolean, :required => false, :label => 'Remove image'
end
end
end
Please try this:
form :html => { :enctype => "multipart/form-data" } do |f|
Also upgrade you activeadmin version to 0.6.6

Rails - has_many build method not saving association

I'm having some trouble trying to make association works.
My models looks like:
advertise.rb
class Advertise < ActiveRecord::Base
belongs_to :user
belongs_to :country
has_many :targets
# has_many :hss, :through => :targets
validates :description, :presence => true
validates :url, :presence => true
validates :country_id, :presence => true
validates :kind, :presence => true
attr_accessible :description, :hits, :url, :active, :country_id, :kind
KINDS = {
'1' => 'Commoditie',
'2' => 'Service',
}
HS = {
'1' => 'Section',
'2' => 'Chapter',
'4' => 'Heading',
'5' => 'SubHeading 1',
'6' => 'SubHeading 2',
}
end
hs.rb
class Hs < ActiveRecord::Base
attr_accessible :code, :kind
has_many :targets
has_many :advertises, :through => :targets
end
target.rb
class Target < ActiveRecord::Base
attr_accessible :advertise_id, :hs_id
belongs_to :advertise
belongs_to :hs
end
advertises_controller.rb
def new
#advertise = Advertise.new
#countries = Country.all
end
def create
#advertise = current_user.advertises.build(params[:advertise])
if #advertise.save
flash[:notice] = 'Advertise created with successful'
redirect_to root_path
else
render :new
end
end
the form for creating a new Ad.
/advertises/new.html.haml
%table.table.table-striped
%tr
%td{:colspan => 2}= advertise.input :url, :required => true
%tr
%td{:colspan => 2}= advertise.input :description, :required => true, :as => :text, :input_html => { :cols => 50, :rows => 3 }
%tr
%td{:colspan => 2}= advertise.input :country_id, :collection => #countries, :as => :select, :label => 'Origin', :required => true
%tr
%td{:colspan => 2}= advertise.input :kind, :collection => Advertise::KINDS.map(&:reverse), :as => :select, :label => 'Type', :required => true
%tr
%td{:colspan => 2}= advertise.input_field :active, as: :boolean, inline_label: 'Active'
=fields_for :targets do |target|
%tr
%td= select_tag :hs_kind, options_for_select(Advertise::HS.map(&:reverse).insert(0,'') )
%td= target.select :hs_id, ''
The hash params:
[3] pry(#<AdvertisesController>)> params
=> {"utf8"=>"✓",
"authenticity_token"=>"fOdn4NYLg/4HXruWURZPf9DYVT4EQzbaTRTKZvX1ugY=",
"advertise"=>
{"url"=>"http://test.com",
"description"=>"test",
"country_id"=>"17",
"kind"=>"2",
"active"=>"1"},
"hs_kind"=>"2",
"targets"=>{"hs_id"=>"487"},
"commit"=>"Create Advertise",
"action"=>"create",
"controller"=>"advertises"}
The hash seems ok to me, but it creates only the Advertise, and not creates the target for the advertise associated.
Any though? Maybe a wrong model association.
Thanks in advance.
try changing
=fields_for :targets do |target|
to
= advertise.fields_for :targets do |target|
and add the following to advertise.rb
accepts_nested_attributes_for :targets
attr_accessible :targets_attributes # just add targets_attributes to attr_accessible
be warned that when you do this, advertise objects that has no targets will not show the fields for targets. you have to build a new target object associated to advertise in order to show the fields
# example: on the new action of the controller
#advertise = Advertise.new
#advertise.targets.build

Not null fields for ActiveAttr

I'm having issues enforcing a field to not be nil within ActiveAttr::Model.
Is there an elegant way of enforcing this constraint within the model instead of defining it in the controller? Or am I testing incorrectly for the scenario?
Model:
class Message
include ActiveAttr::Model
attribute :name, :presence => true, :allow_nil => false, :allow_blank => false
attribute :email, :presence => true
attribute :content, :presence => true
validates_format_of :email, :with => /^[-a-z0-9_+\.]+\#([-a-z0-9]+\.)+[a-z0-9]{2,4}$/i
validates_length_of :content, :maximum => 500
end
RSpec:
module MessageSpecHelper
def valid_message_attributes
{
:name => "Walter White",
:email => "walter#hailtheking.com",
:content => "I am the one who knocks"
}
end
end
it "should have error on name (alternate with nil)" do
#message.attributes = valid_message_attributes.except(:name => nil)
#message.should have(1).error_on(:name)
end

Is it possible to combine with_options and :if for conditional validations?

I'm trying to use with_options to group my conditional validations together for admin users.
The second validation for username uniqueness ends up overriding the with_options condition.
Is there a better way to do this? Or should I just forget about with_options and write two separate statements?
with_options :if => Proc.new { |user| user.admin? } do |admin|
admin.validates :email, :presence => true
admin.validates :username, :uniqueness => true, :if => Proc.new { |user| user.category == "customized_username" }
end
If you only have these two validations, I don't think it's a bad idea to drop the with_options block and just add the conditions directly to each validation:
admin.validates :email, :presence => true, :if => Proc.new { |user| user.admin? }
admin.validates :username, :uniqueness => true, :if => Proc.new { |user| user.admin? && user.category == "customized_username" }
Another thing you may want to consider is Single table inheritance (STI) instead of using a boolean field. I would recommend this if you find yourself doing user.admin? all over your application. Using STI, you would have regular users and Admin users and each could contain different logic for each class. The only real change you'd need to make is changing your "admin" field to "type" and making it a string:
class User < ActiveRecord::Base
end
class AdminUser < User
validates :email, :presence => true
validates :username, :uniqueness => true, :if => Proc.new { |user| user.category == "customized_username" }
end
You should use two lines, however, it is cleaner to have method than repeat the same logic in Proc.
validates :email, :presence => true, :if => :admin?
validates :username, :uniqueness => true, :if => [:admin?, :custom_user?]
def custom_user?
category == "customized_username"
end
Use unless instead:
with_options :unless => Proc.new { |user| !user.admin? } do |admin|
admin.validates :email, :presence => true
admin.validates :username, :uniqueness => true, :if => Proc.new { |user| user.category == "customized_username" }
end

Only validate an Rails3 Model when an value entered

I need to validate a filed called phone_number in my rails3 app. This filed is optional but when a user enter a phone_number i will check the format. The RSpec2 test runs fine but when i go to the sign_up view and don't touch the phone_number field i become an "Phone number is too short (minimum is 6 characters)" and "Phone number is invalid" error.
What is the problem in my model? My target is to validate the phone_number if a user enter this if the number blank i will save an nil in my database.
This is my User model:
class User < ActiveRecord::Base
belongs_to :address
accepts_nested_attributes_for :address
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable, :lockable and :timeoutable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :confirmable, :lockable, :validatable
# Setup accessible (or protected) attributes for your model
attr_readonly :username
attr_accessible :email, :password, :password_confirmation, :remember_me, :phone_number, :username, :newsletter, :address_attributes
validates :username, :presence => true, :uniqueness => true, :length => {:minimum => 4, :maximum => 16 }, :format => { :with => /\A[a-z0-9][a-z0-9._-]*\z/i }
validates :phone_number, :length => {:minimum => 6, :maximum => 25}, :format => { :with => /\A\S[0-9\+\/\(\)\s\-]*\z/i }, :allow_nil => true
validates :address, :presence => true
end
My Rspec Method to test the phone_number:
it "should be valid without an phonenumber" do
Factory.build(:user, :phone_number => nil).should be_valid
end
it "should be invalid with an invalid phonenumber" do
invalid_phonenumbers.each do |invalid|
Factory.build(:user, :phone_number => invalid).should_not be_valid
end
end
it "should be valid with an valid phonenumber" do
valid_phonenumbers.each do |valid|
Factory.build(:user, :phone_number => valid).should be_valid
end
end
def invalid_phonenumbers
["Hans Wurst","+49 221 Hans","Gebe ich nicht ein"," ","110",""]
end
def valid_phonenumbers
["+492203969534","0221/549534","0800-2222 800","+49-0221-2222-390","+49 (221) / 549534 - 23","+49 (0) 221 / 549534 - 23","0221269534"]
end
try this instead of :allow_nil => true, :allow_blank => true
validates :phone_number, :length => {:minimum => 6, :maximum => 25}, :format => { :with => /\A\S[0-9\+\/\(\)\s\-]*\z/i }, :allow_blank => true

Resources