Rails3: Display validate errors in a multi-model Form? - ruby-on-rails

Is posible create this kind forms with displaying errors like a simple model?
http://i.imgur.com/8t6ef.png
I get create two models... but if I fill incorrectly the form.. the errors messages won't appears and error Rails screen say me, for example, "validation failed: field1 can't be blank..."
http://i.imgur.com/6KvVh.png
Models:
class Step < ActiveRecord::Base
#validates
validates :tree_id, :presence => true, :numericality => true
validates :is_first, :presence => true, :length => {:maximum => 1}
validates :status, :presence => true, :numericality => true
validates :step_type_id, :presence => true
#relations
belongs_to :step_type
belongs_to :tree
has_many :statements
accepts_nested_attributes_for :statements
end
class Statement < ActiveRecord::Base
#validates
validates :step_id, :presence => true, :numericality => true
validates :title, :presence => true, :length => {:maximum => 255}
validates :statement, :presence => true
validates :help, :presence => true
validates :is_last_version, :presence => true, :length => {:maximum => 1}
#relations
belongs_to :step
has_many :transitions
end
any example or suggestions?

Do you have the following lines in your view?
<% if #statement.errors.any? %>
<% flash[:notice] = "Please correct!" %>
<% for message in #statement.errors.full_messages %>
<li class="cf-messages-li"><%= message %></li>
<% end %>
<% end %>

Related

Rails 4 - select related records

On my application, I have an object for many-to-many relationships called "selection"
class Selection < ActiveRecord::Base
belongs_to :question
belongs_to :projecttype
end
and 2 objects to relate to each other
class Projecttype < ActiveRecord::Base
has_many :selections
has_many :questions, :through => :selections
validates :projecttype, uniqueness: true, length: { is: 3 }
validates :name, presence: true
mount_uploader :image, ImageUploader
end
And...
class Question < ActiveRecord::Base
has_many :selections
has_many :projecttypes, :through => :selections
validates :question, presence: true
validates :comment, presence: true, length: { minimum: 5}
validates :sequence, presence: true
end
Now in my edit form for the projecttype, I want to be able to select related questions (using check boxes).
<div class="row">
<div class="col-md-2"><%= f.label :selection %></div>
<div class="col-md-4"><%= f.select :selection, {}, {:multiple => true, :style => "width:100%; border:none" } %></div>
</div>
Have tried options_for_selection and _from_collection and don't anymore know what to do as I get many errors.
what should the f.select code be?
I'm a little rusty with Rails now, but it should be something like this.
<%= f.select :selection, Selection.all.collect {|x| x.name}, {}, :multiple => true %>
and don't forget to add
def post_params
params.require(:post).permit(:title, :body, category_ids: [])
end
to your selection.rb file

Validates presence of THIS or THAT

I have a form where the user is prompt to enter a title and either :this or :that. A user can't enter both fields.
<% f.input :title%>
<% f.input :this %>
<% f.input :that%>
for my :title i have in my Model
validates :title, :presence => true
How can i pass a validation for either :this or :that
You can do this
validates :that, :presence => true, :if => Proc.new {this.blank?}
validates :this, :presence => true, :if => Proc.new {that.blank?}
Wouldn't just the first line be sufficient?
validates :that, :presence => true, :if => Proc.new {this.blank?}
If 'this' is blank and so is 'that', the first line would fail validation, so you wouldn't need the second line.

Handling model requirements within the same view?

First and foremost, thanks for taking time to read and respond to my questions. I really appreciate it.
I'm not looking for the exact code on how to achieve the following but more of a direction or path I should follow.
Users that are logged in can create different courses. I've added a requirement (a provider) for each course and I want the user to have at least one provider associated (using rolify for this) to them before doing so but I'd like this to be on the same view (courses#new)
I've tried the following:
Nested forms (Doesn't work since I require at least one provider upon course creation)
Adding the providers#new in a modal on the page (can't call a controller from another one using form_form(#provier)
I've thought of the following:
Redirect the users to providers#new if they haven't created one first
Add a modal with a form_tag element that creates a provider and then refreshes the underlying page.
What are your thoughts? Better ideas?
Thanks!
Francis
My courses#new (_form) view
<%= simple_form_for(#course) do |f| %>
<%= f.error_notification %>
<%= f.input :name %>
<%= f.input :description, as: :text, input_html: { rows: '2' } %>
<%= f.association :provider, :value_method => :id, collection: Provider.with_role(:provider_admin, current_user), input_html: { class: 'input-large' }, include_blank: false %>
<div class="form-actions">
<%= f.button :submit, :class => 'btn-primary' %>
<%= link_to "Cancel", :back, class: 'btn' %>
</div>
<% end %>
models/provider.rb
class Provider < ActiveRecord::Base
attr_accessible :description, :name
validates :name, :presence => true
validates :description, :presence => true
validates :name, :length => { :minimum => 6, :maximum => 100 }
validates :description, :length => { :minimum => 6, :maximum => 100 }
has_many :courses
end
models/course.rb
class Course < ActiveRecord::Base
attr_accessible :description, :name, :provider_id
validates :name, :presence => true
validates :name, :length => { :minimum => 6, :maximum => 100 }
validates :description, :presence => true
validates :description, :length => { :minimum => 6, :maximum => 256 }
validates :provider_id, :presence => true
belongs_to :provider
has_many :sessions, :dependent => :destroy
end
I like the idea where you do a redirect in courses#new to providers#new when !current_user.provider.any?.
But I would probably go the nested forms way. You can use one form to create a new course and a new provider if a user doesn't have a provider. Have a look at http://railscasts.com/episodes/196-nested-model-form-revised to get a quick idea. I think that this would be best UI wise.

Validate fields only if virt_attribute is false

I have such model:
class Order < ActiveRecord::Base
attr_accessible :**** :phone_number, :receiver, :shipping_id, :street, :totalcost, :user_id, :zip, :use_user_data
attr_accessor :use_user_data
validates :city, :presence => {:message => I18n.t(:city_not_chosen)}
validates :zip, :presence => {:message => I18n.t(:zip_not_chosen)}
validates :street, :presence => {:message => I18n.t(:street__not_chosen)}
validates :building, :presence => {:message => I18n.t(:building_not_chosen)}
validates :phone_number, :presence => {:message => I18n.t(:phone_number_not_chosen)}
validates :receiver, :presence => {:message => I18n.t(:receiver_not_chosen)}
end
As you can see i set in model some field which is non-db field (use_user_data) - virtual attribute...
But how to do, if :use_user_data is false, good and right validate, but when true didn't validate?
i try so:
validates :city, :presence => {:message => I18n.t(:city_not_chosen)}, :unless => :use_user_data
and so
with_options :unless => :use_user_data do |order|
order.validates :city, :presence => {:message => I18n.t(:city_not_chosen)}
end
but it doesn't help me... Why?
Also my form:
= form_for #order do |f|
%div
= f.label :use_user_data , "Использовать данные вашего профиля*: "
= label :use_user_data , "Да"
= f.radio_button :use_user_data, true, :required => true, :id => "use_user_data", :checked => true
= label :use_user_data , "Нет"
= f.radio_button :use_user_data, false, :required => true, :id => "dont_use_user_data"
Also when i write
validates :city, :presence => {:message => I18n.t(:city_not_chosen)}, :if => :use_user_data
i get validation messages... But how to do only if false? And why my solution didn't work?
The form passes "true" or "false" string to the object, not boolean true or false. Since it's a virtual attribute, no typecasting performed. In Ruby, both "true" and "false" are true, so you need to use something to typecast the value
with_options :unless => Proc.new{ |a| a.use_user_data == 'true' } do |order|
order.validates ...
end
Or
with_options :unless => :use_user_data? do |order|
order.validates ...
end
def use_user_data?
use_user_data == 'true'
end
You need to put your :if or :unless conditions in a lambda or Proc.
validates ..., :if => Proc.new { |a| a.use_user_data === false }
This causes the check against :use_user_data to not be evaluated until the above validates line is executed during validation (the Proc is passed as the value to the :if or :unless option to be evaluated by Rails). The Proc will receive the current model attributes as an argument, allowing you to check those attributes (in this case, :use_user_data being false).

How do I bypass validation rules set for a nested attribute in ruby on rails?

I have a micropost form which allows a user to upload a photo and type some content to go with it. The image file field is the nested attribute from my photo model.
It has a validation rule "presence => true". This is not required for microposts. User are allowed to post microposts without images/photos.
How ever I use the same photo model for the users image gallery and a photo is required at the time of form submission so I can't disable this rule.
Is there any way to bypass the validation rule set in my photo model for when I post form the micropost form?
Controller:
def new
#user = User.new
#micropost = Micropost.new(:user_id => users_id)
#micropost.build_photo(:photo_album_id => current_user.photo_albums.find_by_album_title("microposts album").id)
end
Form:
= form_for #micropost, :html => { :multipart => true }, :remote => true do |f|
= f.fields_for :photo do |p|
= p.hidden_field :photo_album_id
= p.text_field :photo_title
= p.file_field :image, :id => "micropost_image"
= f.hidden_field :user_id
= f.text_area :content
= f.submit "Post"
Micropost model:
class Micropost < ActiveRecord::Base
belongs_to :user
has_many :comments, :dependent => :destroy
has_one :photo, :dependent => :destroy
accepts_nested_attributes_for :photo
attr_accessor :username
attr_accessible :content, :user_id, :poster_id, :username, :remote_image_url, :photo_attributes
validates :content, :presence => true, :length => { :maximum => 10000 }
validates :user_id, :presence => true
end
Photo model:
class Photo < ActiveRecord::Base
belongs_to :photo_album
attr_accessible :photo_album_id, :photo_title, :image, :remote_image_url
mount_uploader :image, ImageUploader
alpha_num_non_word_char = /^[a-zA-Z0-9\D_ -]*$/
validates :image, :presence => true
validates :photo_title, :length => { :minimum => 2, :maximum => 50 },
:format => { :with => alpha_num_non_word_char,
:message => "error"
}, :if => :photo_title?
validate :picture_size_validation, :if => "image?"
def picture_size_validation
errors[:image] << "Your photo should be less than 1MB" if image.size > 1.megabytes
end
end
Kind regards
There's an option, :reject_if, you can pass to accepts_nested_attributes_for so that it won't try to create a new photo under certain conditions. It would work like this:
accepts_nested_attributes_for :photo, :reject_if => proc { |attributes| attributes['image'].blank? }
Since you specified the :id of the image field as being 'micropost_image', you might have to reference it within the proc like this instead:
attributes['micropost_image']
One of those two should work.

Resources