I have a rating form with 5 radios and a submit button in it. The problem is when I visit this page, for some reason it tries to submit the form (with 'zero' values, of course). Validations don't let to do this, so it renders error message, which is not pretty.
Rating form:
= simple_form_for #shop.ratings.find_or_create_by(user_id: user_id),
:html => {:id => form_id,
:class => "star_rating_form"} do |f|
= f.hidden_field :shop_id, :value => #shop.id
- if signed_in?
= f.hidden_field :user_id, :value => current_user.id
= f.input :stars,
:label => "",
:collection => [[1], [2], [3], [4], [5]],
:label_method => :last,
:value_method => :first,
:as => :radio_buttons,
:item_wrapper_class => 'inline',
:checked => true
= f.submit
Ratings controller:
class RatingsController < InheritedResources::Base
belongs_to :shop
actions :create, :update
def create
#shop = Shop.find(params[:rating][:shop_id])
super
end
def update
#shop = Shop.find(params[:rating][:shop_id])
super
end
private
def permitted_params
params.permit(:rating => [:stars])
end
I tried to do like super unless params[:rating][:stars] == 0 however, it didn't help.
PS For the rest the form works fine.
I am not sure but is this bcoz you are using find_or_create_by which is right away creating object, try find_or_initialize_by. Or look in javascript somewhere you specified function onload() { form.submit(); } is specified. Hope it may help
Related
I'm quite new with RoR so sorry if I say something not correct.
I have these models.
class Course < ApplicationRecord
has_many :frequencies, inverse_of: :course
belongs_to :subject, optional: true
validates :start_date, presence: true
end
class Frequency < ApplicationRecord
belongs_to :user
belongs_to :course
validates :course, presence: true
validates_presence_of :course
accepts_nested_attributes_for :user, :course
has_many_attached :docs
end
The relationship between Course and Frequency is 1:N but, at the end, I use it as a 1:1 (things changed after defined the models).
This is the view app/views/frequencies/show.html.haml
= simple_form_for #frequency, :url => frequencies_update_path(:id => #frequency.id) do |f|
.panel.panel-primary
.panel-heading
%h4.panel-title= t 'frequencies.upd_frequency'
.panel-body
= f.simple_fields_for :user do |u|
.row
.col-md-4
= u.label t 'frequencies.first_name'
.col-md-4
= u.input :first_name, :label => false, :disabled => true, :input_html => {:id => 'first_name'}
.row
.col-md-4
= u.label t 'frequencies.last_name'
.col-md-4
= u.input :last_name, :label => false, :disabled => true, :input_html => {:id => 'last_name'}
-#= u.hidden_field :id, value: #user_id
.panel.panel-primary
.panel-heading
%h4.panel-title= t 'frequencies.course'
.panel-body
= f.simple_fields_for :course do |u|
.row
.col-md-4
= u.label t 'frequencies.course_start_date'
.col-md-4
= u.input :start_date, :label => false, :disabled => (#frequency.validated? ? true : false), :input_html => {:id => 'course_start_date'}
.
.
.
= f.submit t('button.save'), :class => 'btn btn-primary ' + (current_user.role == $admin_role && #frequency.validated? ? 'disabled' : '')
= link_to t('button.cancel'), request.referer.present? ? request.referer : frequencies_index_path, :class => 'btn btn-default'
This is part of the frequencies_controller.rb
def update
#frequency = Frequency.find params[:id]
#course = Course.find #frequency.course_id
if over_max_hours_in_a_day(frequency_params[:user_attributes][:id], #course)
flash[:danger] = t('flash.max_hours')
render :action => :show and return
end
if #course.update(frequency_params[:course_attributes])
#frequency.docs.attach(frequency_params[:attach][:docs]) if (frequency_params[:attach].present? && frequency_params[:attach][:docs].present?)
flash[:notice] = t('flash.upd')
redirect_to :action => 'index' and return
else
flash[:danger] = #course.errors.full_messages.to_sentence
render :action => :show and return
end
end
def show
#frequency = Frequency.find params[:id]
#subjects = Subject.all
end
I'm able to edit a course from the related frequency's view but I have some strange behaviours:
when I save the validation process occurs but I have the error message only as flash message and not under the involved field (in others simpler views I have the message also under the field)
when I edit some course's fields (from the frequency view) and after I click on the save button it calls the update action but, if it runs inside the over_max_hours_in_a_day if condition, I'm not able to stay on the same view with the modified fields precompiled (but I have the fields like it loads at the beginning show action)
when I press the cancel button after a previous failed edit I remain on the same page instead of come back to the previous view (index view)
I'm not sure if this is due to accepts_nested_attributes_for on a belongs_to model, because I usually see it in a has_many model.
Rails 5 5.2.2
simple_form 4.1.0
Please, can you help me?
Thanks.
separate logic depending on the view (from show / index pages). Create 2 update methods
in case of error just render view again render :show OR render :index
I think it's better move logic of over_max_hours_in_a_day to model
for cancel button don't use referrer because after update it won't work. Pass exact back url using form locals or other way
if you want to hightligh fields - you must call .update, .save method on it with form parameters
I apologize if the title to the question may come off a bit confusing, but I am sincerely having a difficult time putting it into better words.
I am trying to access a single attribute within a fields_for submission in the controller.
My form looks like this:
= form_for #match, :url => matches_search_path, remote: true do |f|
= f.select :sport_id, options_from_collection_for_select(Sport.all, "id", "name"), {:prompt => "Select Sport..."}, class: "form-control"
= f.fields_for #match.build_location do |g|
= g.text_field :zip, :class => "form-control", :value => #user.location.zip, :placeholder => "Zip"
= f.text_field :max_players, :class => "form-control", :placeholder => "Player Limit (in total)"
= f.submit "Search", :class => "btn btn-info"
And the MatchesController like so:
class MatchesController < ApplicationController
before_filter :current_user
def index
#match = Match.new
#user = current_user
end
def new
#match = Match.new
#match.build_location
end
def create
#user = User.find(session[:user_id])
#match = #user.matches.build(match_params)
if #match.save
redirect_to :root, :notice => "Match created."
else
render :new, :alert => "Failed to create match."
end
end
def search
# Get all matches for the searched sport
#results = Match.sport_id(match_params[:sport_id])
#This is where the problem is:
#coordinates = Geocoder.coordinates(match_params[:location][:zip])
#results = #results.select {|result| result.location.distance_from(#coordinates)}
respond_to :js
end
private def match_params
params.require(:match).permit(:sport_id, :name, :description, :choose_teams, :keeping_score, :max_players, :time, location_attributes: [:address, :city, :state, :zip])
end
end
And the route is fine:
# Matches
resources :matches
post 'matches/search', as: :matches_search
The form submits an ajax call to the search method in the MatchesController just fine. The problem is that I get:
undefined method `[]' for nil:NilClass
at the line
#coordinates = Geocoder.coordinates(match_params[:location][:zip])
I tried googling the problem but the closest to this problem I found was here, where when trying to access a "hash within a hash" is to use:
params[:outer_hash][:inner_hash]
which did not work when I used params[:location][:zip], match_params[:location][:zip] or match_params[:location_attributes][:zip].
I verified that the information from the form is being sent to the controller. I just can't seem to access it properly.
What exactly am I doing wrong?
Edit:
Here's the response from the form:
(I blocked out the authenticity_token)
{"utf8"=>"✓", "authenticity_token"=>"XXXXXXXXXXXXXXXXXXXXXXX",
"match"=>{"sport_id"=>"4",
"location"=>{"zip"=>"11211"},
"max_players"=>""},
"commit"=>"Search"}
What I think is happening is that your match_params are not letting in the location params (I'm guessing a match has_one location). Change the line:
#coordinates = Geocoder.coordinates(match_params[:location][:zip])
to:
#coordinates = Geocoder.coordinates(params[:match][:location][:zip])
OR better yet, change your match_params to:
params.require(:match).permit(:sport_id, :name, :description, :choose_teams, :keeping_score, :max_players, :time, location: [:address, :city, :state, :zip])
i want to save a input "email" from static pages to the database. Right now, i have a emails model with a :address field, but i can't save the value when click the submit input.
Layout with form
# layout/website.html.erb
<div>
<%= form_for #email, :url => newsletter_path, :method => :post do |email| %>
<%= email.text_field :address %>
<%= email.submit "Go" %>
<% end %>
</div>
Pages Controller
# controllers/pages_controller.rb
def home
newsletter
end
def newsletter
#email = Email.new(params[:address])
if #email.valid?
redirect_to(request.referer, :notice => "The suscription has been sent successfully.")
else
redirect_to(request.referer, :alert => "Please add an valid email address.")
end
end
Routes
# routes.rb from static pages
get "/home" => 'pages#home', :as => :home
get "/pricing" => 'pages#pricing', :as => :pricing
get "/logo-gallery" => 'pages#logo_gallery', :as => :logo_gallery
get "/blog" => 'pages#blog', :as => :blog
get "/blog/:id" => 'pages#post', :as => :post
get "/contact" => 'pages#contact', :as => :contact
match '/contact' => 'pages#create', :as => :contact, :via => :post
get "/faqs-and-terms" => 'pages#faqs_and_terms', :as => :faqs_and_terms
match "/newsletter" => 'pages#newsletter', :as => :newsletter, :via => :post
Model
# models/email.rb
class Email < ActiveRecord::Base
attr_accessible :address
validates :address, :format => { :with => %r{.+#.+\..+} }, :allow_blank => true
end
With this code, when visit /home right now i'm received:
ActionController::ActionControllerError in PagesController#home
Cannot redirect to nil!
I hope you can help me, what can i do to fix this and get a better code. Thank you.
You should use Email.create(params[:email]) instead of Email.new(params[:address]) to persist records in DB. Also, in your view you code add hidden_field
<%= email.text_field :address %>
<%= hidden_field_tag :referer, :value => request.path %>
<%= email.submit "Go" %>
And then in controller:
redirect_to params[:referer]
UPD
Also, please notice that you should use params[:email] in your controller, not params[:address]. You can invoke raise params.inspect in your controller to inspect params sent by form.
In newsletter action email record is only initialized but not saved. And you have no need to call newsletter method inside home action every time. Just update your code like this.
Pages Controller
# controllers/pages_controller.rb
.....
# no need to call newsletter action here
def home
end
def newsletter
#email = Email.new(params[:email])
if #email.save
redirect_to((request.referer || '/'), :notice => "The suscription has been sent successfully.")
else
redirect_to((request.referer || '/'), :alert => "Please add an valid email address.")
end
end
Layout with form
As #email is not defined in controller, so you should initialize an Email object in form.
# layout/website.html.erb
<div>
<%= form_for Email.new, :url => newsletter_path, :method => :post do |email| %>
<%= email.text_field :address %>
<%= email.submit "Go" %>
<% end %>
</div>
I hope that it should work.
The easy way from our page is
welcome-controller add an email -> second_controller create an new object with the E-Mailadddress.
we have a welcome-controller that shows our welcome-page. At this page you can type an e-mailaddress which will give to an other controller. We work with simple_form
If we that this config.browser_validations = false and enter an "normal" text we get an error on the create action. In the older version, without simple_form we get an validation-error.
If we enable this we get the html5 validation. but when the browser doesn't support html5?
Our model is here
validates :owner_email,
:presence => true,
:format => { :with => /\A[A-Za-z0-9._%+-]+#[A-Za-z0-9.-]+\.[A-Za-z]+\z/ },
:on => :create
Our welcome-view is here
<p>
<h2>Create a list without registration.</h2>
<%= simple_form_for([#list], :html => {:class => 'well' }) do |f| %>
<%= f.input :owner_email, :label => false, :placeholder => 'Your Email.' %>
<%= f.button :submit, "Create", :class => "btn-primary" %>
<% end %>
</p>
Our create-action from the second controller is this
def create
# create a new list and fill it up
# with some default values
#list = List.new(
:title => "List",
:description => "Beschreibung",
:owner_email => "test#domain.com",
:admin_key => generate_admin_key)
#list.update_attributes(params[:list])
respond_with(#list) do |format|
format.html {#
redirect_to :action => "admin", :id => #list.access_key, :status => 301}
end
end
What have we to change that we get errormessages in the html4 version? can everyone help us please?
Just add a :message parameter. Unless you changed simple_form configuration, message errors should be shown on the right side of the field with errors.
validates :owner_email,
:presence => true,
:format => { :with => /\A[A-Za-z0-9._%+-]+#[A-Za-z0-9.-]+\.[A-Za-z]+\z/ ,
:message => 'Invalid e-mail! Please provide a valid e-mail address'},
:on => :create
I'm dealing with this legacy form for creating a new conversation. It has two fields : Name and description (the first comment of a conversation)
Here are the fields :
_fields.haml
.conversation_title= f.label :name, t('.name')
.clear
= f.text_field :name, :style => 'width: 230px'
= errors_for f.object, :name
if f.object.new_record?
= f.fields_for :comments, f.object.comments.build do |comment_fields|
.conversation_title= comment_fields.label :description, t('.description')
= comment_fields.text_area :body, :placeholder => t("comments.new.conversation"), :style => 'width: 545px'
= errors_for f.object, :comments
from the new view for conversations
= form_for [#current_project, #conversation], :html => { 'data-project-id' => #current_project.id, :name => 'form_new_conversation', :multipart => true } do |f| #, :onsubmit => 'return validate_form_new_conversation(form_new_conversation)'
= render 'fields', :f => f, :project => #current_project
= render 'watcher_fields', :f => f, :project => #current_project
The associated validations are :
conversation.rb
validates_presence_of :name, :message => :no_title, :unless => :simple?
validates_presence_of :comments, :message => :must_have_one, :unless => :is_importing
comment.rb
validates_presence_of :body, :unless => lambda { |c| c.task_comment? or c.uploads.to_a.any? or c.google_docs.any? }
For some reason, the proc associated to fields with error from base.rb
##field_error_proc = Proc.new{ |html_tag, instance| "<div class=\"field_with_errors\">#{html_tag}</div>".html_safe }
doesn't get called for the text area, so it doesn't change its style to make it turn red. It does for the :name field. Error messages get displayed properly
What am I missing?
Thanks!
The validation would be for the Comment model (rather than the Conversation model) on the body field. Check to make sure that validation exists. You can debug this to make sure that comment_fields.object has an error set on the body field, too.
I failed to notice one important part of this line in your code:
= f.fields_for :comments, f.object.comments.build do |comment_fields|
You call f.object.comments.build which means that you will always end up with a new instance of Comment (rather than the instance that was validated in the controller).
To avoid this you can build a comment in the controller. If you are using the normal restful actions you probably have two places where you want to build a comment. First in the new action and second, in the create action.
def new
#conversation = Conversation.new
#conversation.comments.build # Create a blank comment so that the fields will be shown on the form
end
def create
#conversation = Conversation.new(params[:conversation])
respond_to do |format|
if #conversation.save
format.html { redirect_to conversations_path }
else
format.html {
#conversation.comments.build if #conversation.comments.blank? # Create a blank comment only if none exists
render :action => "new"
}
end
end
end