Nested form validations not working in rails app - ruby-on-rails

My validations are not working for a nested form - messages, which is in other models show page.
Here's the code:
Reserve Online:
<%= form_for([#trip, #trip.messages.build]) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= f.text_field :name, :class => "span3", :placeholder => "Name:" %>
<%= f.text_field :email, :class => "span3", :placeholder => "Email:" %>
<div class="h">
<%= f.text_field :subject, :class => "h", :value => (#trip.title) %>
</div>
<%= f.text_area :body, :class => "input-xlarge3", :placeholder => "Message:", :id => "textarea", :rows => "3" %>
<%= f.submit :class => " btn btn-primary btn-large ", :value => "Send Message" %>
<% end %>
</div>
Message.rb
class Message < ActiveRecord::Base
belongs_to :trip
attr_accessible :name, :email, :subject, :body
validates_presence_of :name
validates_format_of :email, :with => /^[-a-z0-9_+\.]+\#([-a-z0-9]+\.)+[a-z0-9]{2,4}$/i
validates_length_of :body, :maximum => 500
end
an the messages_controller.rb
class MessagesController < ApplicationController
def create
#trip = Trip.find(params[:trip_id])
#message = #trip.messages.create(params[:message])
if #trip.messages.create
MessageMailer.send_message(#message).deliver
redirect_to thank_you_path
else
redirect_to trip_path(#trip)
end
end
end
_error_messages.rb
<% if object.errors.any? %>
<div id="error_explanation">
<div class="alert alert-error">
The form contains <%= pluralize(object.errors.count, "error") %>.
</div>
<ul>
<% object.errors.full_messages.each do |msg| %>
<li>* <%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
The whole code above works fine, but the validation part is simply ignored. And I don't see any errors.
So I Can't figure out what I'm doing wrong. Can You help?
Thank you!

I think there is a problem in your controller:
def create
#trip = Trip.find(params[:trip_id])
#message = #trip.messages.create(params[:message])
# the following line doesnt make sense
# you're recreating an empty message
# it should be something like "if #message.valid?"
if #trip.messages.create
MessageMailer.send_message(#message).deliver
redirect_to thank_you_path
else
redirect_to trip_path(#trip)
end
end
Try to fix that and see if it helps.

Related

Nested attributes (Paperclip) validation

I'm working on a nested form where a user when creating a Screen should also attached an image (a separate model called Screenshot). I'm trying to validate the presence of the attachment before saving the new Screen to the db. I tried to validate the presence of the attachment in the Screenshot model, but that only precent Screenshot to be saved, while it still creates a Screen.
Here's my models:
class Screen < ActiveRecord::Base
belongs_to :project
has_many :screenshots
validates :name, presence: true
accepts_nested_attributes_for :screenshots
validates_presence_of :screenshots
end
class Screenshot < ActiveRecord::Base
belongs_to :screen
has_attached_file :image, :styles => { :medium => "300x300>", :thumb => "100x100>" }
end
here's my controller:
def create
#screen = Screen.create(screen_params)
if #screen.save
flash[:notice] = "A new screen has been added to this project"
redirect_to [#screen.project]
else
render :action => 'new'
end
end
And lastly here's my form:
<%= form_for ([#project, #screen]), :html => { :multipart => true } do |f| %>
<% if #screen.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#screen.errors.count, "error") %> prohibited this screen from being saved:</h2>
<ul>
<% #screen.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.hidden_field :project_id %>
</div>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :description %><br>
<%= f.text_field :description %>
</div>
<%= f.fields_for :screenshots, #screen.screenshots.build do |s| %>
<%= s.hidden_field :screen_id, :value => #screen.id %>
<%= s.hidden_field :version, :value => "1" %>
<%= s.label :image %><br>
<%= s.file_field :image %>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Any help to this noob is greatly appreciated.
Several things for you:
Form
You shouldn't build new objects in the form itself. That needs to happen in the controller's new function
<%= f.fields_for :screenshots do |s| %>
<%= s.hidden_field :screen_id, :value => #screen.id %>
<%= s.hidden_field :version, :value => "1" %>
<%= s.label :image %><br>
<%= s.file_field :image %>
<% end %>
You can declare them like this:
def new
#screen = Screen.new
#screen.screenshots.build
#any more build declarations go here
end
Verification
I believe you should put the verification into the screnshots model, as the nested parameters are passed directly to the corresponding model. I'm not sure on that though.
In the screenshots model, I would put the validates_presence_of :screenshots, with the name as your Paperclip attachment's name

AssociationTypeMismatch (Object expected, got HashWithIndifferentAccess) in Rails app

I'm getting a AssociationTypeMismatch Error and I'm not sure where I'm making a mistake. I'm pretty new to Rails so I'm guessing I'm making some silly mistake. I've checked my syntax and compared it against AssociationTypeMismatch Error on Ruby on Rails app
... but I still can't seem to catch the error.
Here's my models
class User < ActiveRecord::Base
attr_accessible :email, :full_name, :password, :password_confirmation, :preference
has_secure_password
validates_uniqueness_of :email
validates_presence_of :full_name
has_one :preference, :dependent => :destroy
accepts_nested_attributes_for :preference
end
class Preference < ActiveRecord::Base
attr_accessible :background_fill, :background_position, :layout
belongs_to :user
end
Here's my controller:
def new
#user = User.new
#user.build_preference
end
def create
#user = User.new(params[:user])
if #user.save
session[:user_id] = #user.id
redirect_to root_url, notice: "Thanks for signing up!"
else
render "new"
end
end
Here's my view:
<%= form_for #user do |f| %>
<% if #user.errors.any? %>
<div class="error_messages">
<h2>There's an error!</h2>
<ul>
<% #user.errors.full_message.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<%= f.label :full_name %>
<%= f.text_field :full_name, :class => "target", :placeholder => "Your full name", :maxlength => "55", :autofocus => "autofocus" %>
<%= f.label :email %>
<%= f.email_field :email, :class => "target", :placeholder => "example#gmail.com", :maxlength => "55" %>
<%= f.label :password %>
<%= f.password_field :password, :class => "target", :placeholder => "Enter a password", :maxlength => "55" %>
<%= f.label :password_confirmation, "Confirmation" %>
<%= f.password_field :password_confirmation, :class => "target", :placeholder => "Enter your password again", :maxlength => "55" %>
<%= f.fields_for :preference do |builder| %>
<%= builder.hidden_field :layout, value: params[:layout] %>
<%= builder.hidden_field :background_fill, value: params[:background_fill] %>
<%= builder.hidden_field :background_position, value: params[:background_position] %>
<% end %>
<%= f.submit "Create an Account", :class => "button cta" %>
<% end %>
And my parameters
{"utf8"=>"✓",
"authenticity_token"=>"[redacted]=",
"user"=>{"full_name"=>"test",
"email"=>"test#example.com",
"password"=>"[FILTERED]",
"password_confirmation"=>"[FILTERED]",
"preference"=>{"layout"=>"layout-3",
"background_fill"=>"restaurant-2",
"background_position"=>"position-center"}},
"commit"=>"Create an Account"}
Edit:
The error I get is Preference(#70124732528700) expected, got ActiveSupport::HashWithIndifferentAccess(#70124687315200). My understanding is that #user.build_preference and accepts_nested_attributes_for :preference would just work on its own.
Do I need to create a def preferences_attributes= as per?
http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-fields_for
Update
Okay so I think I'm getting a bit closer. Poking around in the rails console, I figured I need to create Preference.new inside the UserController before I can pass in the hash. Since I'm not sure sure what build_preference does exactly, I'm not having any luck yet.
I've tried adding #user.preference = Preference.new above build preference and changing f.field_for :preference to f.field_for #user.preference but I'm still getting the same error.
Update 2
For anyone else that's stuck on this problem, the answer is to change f.field_for :preference to f.field_for :preference_attributes. See comment below by zetetic.
it is:
attr_accessible :preference_attributes
and in your form:
<%= f.fields_for :preference_attributes do |builder| %>
...
Give a shot.
In your User model, try to add :preference_attributes to your attr_accessible line.
class User < ActiveRecord::Base
attr_accessible :email, :full_name, :password, :password_confirmation, :preference_attributes
.. # rest of your code goes here
end

Can't get nested_form to show validation errors

I haven't had a problem with validations before but this time I am having issues with nested_form validations. I am using Twitter Bootstrap and can get flash errors to show with, say, this:
def create
#recipe = current_user.recipes.new(params[:recipe])
if #recipe.save
redirect_to my_recipes_path, :notice => "Thanks #{current_user.name} Recipe sucessfully created."
else
render :action => 'new'
end
end
For my flash messages I use this in my app/layouts
<% flash.each do |name, msg| %>
<div class="alert alert-<%= name == :notice ? "success" : "error" %>">
<a class="close" data-dismiss="alert">×</a>
<%= content_tag :div, msg, :id => "flash_#{name}" if msg.is_a?(String) %>
</div>
<% end %>
So I thought I would try and just get one of the validators working, so my model
class Recipe < ActiveRecord::Base
belongs_to :user
delegate :name, :to => :user, :prefix => :user, :allow_nil => true
belongs_to :country
has_many :ingredients
has_many :preperations
has_many :favourites
validates_presence_of :dish_name
and my form
<%= nested_form_for #recipe do |f| %>
<div class="field_with_errors">
<%= f.label :dish_name, "Dish Name" %>
<%= f.text_field :dish_name, :placeholder => "Enter Dish Name" %>
</div>
<%= f.label :country_id, "Country Of Origin" %>
<%= f.collection_select(:country_id, Country.all, :id, :name, :prompt => 'Please select country') %>
<%= f.label :category, "Category" %>
<%= f.select :category, [['Starter'], ['Main Course'], ['Desserts'], ['Vegeterian']], {:include_blank => 'Please Select'} %>
<%= f.label :difficulty, "Difficulty Level" %>
<%= f.select :difficulty, [['Beginner'],['Intermediate'],['Expert']], {:include_blank => 'Please Select'} %>
<%= f.label :preperation_time, "Preperation Time (Mins)" %>
<%= f.select :preperation_time, [['15-30 Mins'],['30-60 Mins'],['60-120 Mins']], {:include_blank => 'Please Select'} %>
<%= f.fields_for :ingredients do |ing| %>
Ingredient<br>
<%= ing.text_field :ingredient_name , :placeholder => "Enter Ingredient Here" %><br>
<% end %>
<%= f.link_to_add "Add an Ingredient", :ingredients %><br>
<%= f.fields_for :preperations do |prep| %>
Preperation Step<br>
<%= prep.text_field :prep_steps , :placeholder => "Enter step Here" %><br>
<% end %>
<%= f.link_to_add "Add a step", :preperations %><br>
<%= f.label :description, "Description of Recipe" %>
<%= f.text_area :description, :size=> "60x10" %></br>
<%= f.file_field :avatar %><br>
<%= f.submit "Submit Recipe" %>
<% end %>
I am fairly new to Rails so I may have missed something fundamental, or is it because it is a nested form and it behaves differently?
Edit
Output of <%= flash debug %>:
--- !ruby/object:ActionDispatch::Flash::FlashHash
used: !ruby/object:Set
hash: {}
closed: false
flashes: {}
now:
It seems you're not actually providing your flash hash with any messages to work with. A quick solution might be something like:
def create
#recipe = current_user.recipes.new(params[:recipe])
if #recipe.save
redirect_to my_recipes_path, :notice => "Thanks #{current_user.name} Recipe sucessfully created."
else
flash[:error] = #recipe.errors.full_messages.to_sentence
render :action => 'new'
end
end

Can't mass-assign protected attributes: quantities

I'm getting this error:
Can't mass-assign protected attributes: quantities
I looked up all the threads concerning this issue in the site, but couldn't find something to answer my problem. Here are the code snippets:
product.rb
class Product < ActiveRecord::Base
attr_accessible :name, :quantities_attributes
has_many :quantities
accepts_nested_attributes_for :quantities, :allow_destroy => :true,
:reject_if => proc { |attrs| attrs.all? { |k, v| v.blank? } }
new.html.erb
<% if #was_submitted %>
<%= form_for(:new_product_array, :url => products_path) do |f| %>
<% prefix ||= 0 %>
<% #new_product_array.each do |n| %>
<% n.quantities.build %>
<% prefix += 1 %>
<%= f.fields_for(prefix.to_s ) do |child| %>
<div class="field">
<%= child.label :name %><br />
<%= child.text_field :name%>
</div>
<%= render :partial => 'quantities/form',
:locals => {:form => child} %>
<% end %>
<% end %>
<div class="actions">
<%= submit_tag :submit %>
</div>
<% end %>
<% else %>
<%= form_tag new_product_path, :method => 'get' do %>
<p align=center>
How many Items are you Adding? (1-100)
<%= number_field_tag 'amount', 1, :in => 1...100 %>
</br>
To which storage?
<%= number_field_tag 'storage', 1, :in => 1...100 %>
<%= submit_tag "Next", :name => 'submitted' %>
</p>
<% end %>
<% end %>
<%= link_to 'Back', products_path %>
product_controller.rb
def new
#product = Product.new
if params['submitted']
#was_submitted = true
#amount_form = params['amount']
#new_product_array = []
(1..#amount_form.to_i).each do
#new_product_array << Product.new
end
#storage_form = params['storage']
else
#was_submitted = false
end
respond_to do |format|
format.html # new.html.erb
format.json { render :json => #product }
end
end
def create
i=0
logger.info params[:new_product_array].inspect
params[:new_product_array].each do |new_product|
if new_product.last[:name] != nil
#new_product_array[i] = Product.new(new_product.last)
#new_product_array[i].save
i+=1
end
end
redirect_to(products_path)
end
quantity.rb
class Quantity < ActiveRecord::Base
belongs_to :product
attr_accessible :amount, :storage
end
quantity/_form.html.erb
<%= form.fields_for :quantities do |quant| %>
<div class="field">
<%= quant.label :storage %><br />
<%= quant.number_field :storage %>
</div>
<div class="field">
<%= quant.label :amount %><br />
<%= quant.number_field :amount %>
</div>
<% unless quant.object.nil? || quant.object.new_record? %>
<div class="field">
<%= quant.label :_destroy, 'Remove:' %>
<%= quant.check_box :_destroy %>
</div>
<% end %>
<% end %>
Overall what Im trying to do, is ask the user how much products to add, then make a form with the number of fields the user specifies and with one submit button add all of the products, whereas when you add a product you also add a quantity record which holds more information on the product.
You need a line like this:
attr_accessible :name, :quantities_attributes, :quantities
You have very bad code, it can be much simplier 100%.
Your problem is that form dont' know nothing about your resource (product), so it can't render 'smartly' fields "quantities_attributes", it renders "quantities" instead.

setting user alias as message recipient

I have two models, user and treating (which you can think of as a message).
User:
class User < ActiveRecord::Base
attr_accessible :name, :email, :password, :password_confirmation
has_secure_password
has_many :sent_treatings, :foreign_key => "requestor_id", :class_name => "Treating", dependent: :destroy
has_many :received_treatings, :foreign_key => "requestee_id", :class_name => "Treating", dependent: :destroy
end
Treating:
class Treating < ActiveRecord::Base
attr_accessible :intro, :proposed_date, :proposed_location
validates :intro, presence: true, length: { maximum: 190 }
validates :requestor_id, presence: true
validates :requestee_id, presence: true
belongs_to :requestor, class_name: "User"
belongs_to :requestee, class_name: "User"
default_scope order: 'treatings.created_at DESC'
end
I'm having trouble in my treatings controller setting 'requestee':
class TreatingsController < ApplicationController
before_filter :signed_in_user
def create
requestee = ?
requestor = current_user
#received_treating = requestee.received_treatings.build(params[:treating])
#received_treating.requestor = requestor
if #received_treating.save
flash[:success] = "Treating request sent!"
redirect_to users_path
else
render 'static_pages/home'
end
end
end
The question mark I tried to replace with: User.find(params[:id]), hoping that the user in the current 'users/show' view would be found, but I get this error:
Couldn't find User without an ID
I also tried User.find(params[:treating][:requestee_id]), but this didn't work either. Any ideas?
Thanks!
EDIT:
views/shared/_treating_form.html.erb (this references #received_treating in the users controller, show action):
<div class="field">
<%= f.text_area :intro, placeholder: "Write your introduction here..." %>
</div>
<%= f.submit "Send", class: "btn btn-large btn-primary" %>
EDIT: adding other user profile page:
<% provide(:title, #user.name) %>
<div class="row">
<aside class="span4">
<section>
<h1>
<%= gravatar_for #user %>
<%= #user.name %>
</h1>
</section>
<% if signed_in? %>
<section>
<%= render 'shared/treating_form' %>
</section>
<% end %>
</aside>
<div class="span8">
<% if #user.received_treatings.any? %>
<h3>Treating requests (<%= #user.received_treatings.count %> received)</h3>
<ol class="treatings">
<%= render #received_treatings %>
</ol>
<%= will_paginate #received_treatings %>
<% end %>
</div>
</div>
I think just adding #user.id in a hidden_field would work.
<%= f.hidden_field :requestee_id, :input_html => { :value => #user.id }
<div class="field">
<%= f.text_area :intro, placeholder: "Write your introduction here..." %>
</div>
<%= f.submit "Send", class: "btn btn-large btn-primary" %>
You could also populate the field doing
<%= form_for #user.received_treatings.build do %>
<%= f.hidden_field :requestee_id %>
....
On the controller just do
#received_treating = current_user.sent_treatings.build params[:treating]
I have some doubts if this works but I think it should help you out.

Resources