I'm creating a basic blog application and I'm running into issues displaying error messages when a user tries to submit a blank comment. Instead of getting a nice looking error message, an active record error message with the correct validation erorrs. Such as
ActiveRecord::RecordInvalid in CommentsController#create
Validation failed: Name can't be blank, Email can't be blank
In my article/show view I have the following code:
<%= form_for([#article, #article.comments.build]) do |f| %>
<%= render "shared/error_messages", :target => #article %>
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :email %><br />
<%= f.text_field :email %>
</div>
<div class="field">
<%= f.label :body %><br />
<%= f.text_area :body %>
</div>
<p><%= f.submit %></p>
<% end %>
My error messages partial looks like this:
<% if target.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(target.errors.count, "error") %> prohibited this record from being saved:</h2>
<ul>
<% target.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
I know the answer is simple but I can't figure it out.
Create action in comments controller:
def create
#article = Article.find(params[:article_id])
#comment = #article.comments.build(params[:comment])
respond_to do |format|
if #comment.save
format.html { redirect_to(#article, :notice => 'Comment was successfully created.') }
format.xml { render :xml => #article, :status => :created, :location => #article }
else
format.html { render :action => "articles/show" }
format.xml { render :xml => #comment.errors, :status => :unprocessable_entity }
end
end
I had a similar problem. everything seemed to work fine, but I was not getting any errors
The solution i found is to build the comment in article#show instead of the view:
#article = Article.find(params[:id])
#comment = #article.comments.build(params[:comment])
and in your articles#show don't use #article.comments.build but #comment:
<%= form_for([#article, #comment]) do |f| %>
<%= render 'shared/error_messages', :object => f.object %>
<p><%= f.submit %></p>
<% end %>
make sure you build the comment in your comment#create as well (you really have no choice though :P)
also, I don't know if it matters (i'm pretty new to ruby), but I think you need to pass f.object instead of #comment.
I think you're saying that you get the big grey-on-white error page, right?
Check the backtrace, but I suspect that this is coming from the create action in the controller, not the view.
If your controller uses save! with the ! at the end, that means that it will raise an error if the record is invalid. save, on the other hand, returns true or false and lets you use simple branch logic to decide how to react.
If my hunch on save! isn't right, though, please post controller code so we can dig deeper :) Thanks!
The solution was to direct the comments created action back to the correct controller/action and target #comment in my error message partial.
Final view
<%= form_for([#article, #article.comments.build]) do |f| %>
<%= render "shared/error_messages", :target => #comment %>
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :email %><br />
<%= f.text_field :email %>
</div>
<div class="field">
<%= f.label :body %><br />
<%= f.text_area :body %>
</div>
<p><%= f.submit %></p>
<% end %>
Final create action in comments controller
def create
#article = Article.find(params[:article_id])
#comment = #article.comments.build(params[:comment])
respond_to do |format|
if #comment.save
format.html { redirect_to(#article, :notice => 'Comment was successfully created.') }
format.xml { render :xml => #article, :status => :created, :location => #article }
else
format.html { render :action => "articles/show" }
format.xml { render :xml => #comment.errors, :status => :unprocessable_entity }
end
end
Related
So im sending a param from a view to a view of another controller
<%= render template: 'dishes/new', :id => #restaurant.id %>
and this is my other controller view:
def new
#dish = Dish.new
#id = params[:id]
end
def create
#dish = Dish.new(dish_params)
respond_to do |format|
if #dish.save
format.html { redirect_to #restaurant, notice: 'dish was successfully created.' }
format.json { render action: 'show', status: :created, location: :restaurant }
else
format.html { render action: 'show', location: :restaurant }
format.json { render json: #restaurant.errors, status: :unprocessable_entity }
end
end
end
private
def dish_params
params.require(:dish).permit( :avatar, :name, :description, [:id])
end
and this is my view who calls the form:
#new.html.erb
<h1>Add a new dish</h1>
<%= render 'dishes/dish_form' %>
then here is the form:
<%= form_for #dish, :url => { :controller => "dishes", action_name => "create" } do |f| %>
<div class="field">
<%= f.label :dish_name %>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :description %>
<%= f.text_field :description %>
</div>
<div class="field">
<%= f.label :image %>
<%= f.file_field :avatar %>
</div>
<div class="actions">
<%= f.submit 'Add new dish' %>
</div>
<% end %>
but when i try to save it i got this error:
I think your problem comes in when you are expecting your render template: 'dishes/new' to hit your DishesController. That is not what is happening when you are calling the render.
What you're doing is telling rails to load into your current view the template for 'dishes/new', and you're passing 'dishes/new' a variable that it can access when rendering. You aren't sending a param to a controller.
If you want to keep the current set up you have right now, you can make it work with some tweaking.
I'm going to assume that your Dish model belongs to Restaurant, and therefore has restaurant_id as a column. If that is true, then you can add a hidden field to your form for dishes, called restaurant_id, and update your permitted params in your controller to allow the restaurant id to be set on the dish.
Your form would look like this:
<%= form_for #dish, :url => { :controller => "dishes", action_name => "create" } do |f| %>
<%= f.hidden_field :restaurant_id, value: id %>
...
<% end %>
Your permitted params in your controller would look like this:
def dish_params
params.require(:dish).permit(:avatar, :name, :description, :restaurant_id)
end
You can get more information on how the rails rendering is working here
The error is saying that your controller named Restaurants does not have an action named "Show".
One solution would be to add the Action with the name "Show" to the restaurant controller.
The other option may be that you actually created the action you wanted, but you named it something other than "Show".
On the community's #show page, I get:
undefined method `comments'
I was wondering why was I get this error?
community_topics_controller.rb
def show
#community_topic = CommunityTopic.find params[:id]
#comment = #community_topic.comments.build
#community_topic.comments.pop
respond_to do |format|
format.html # show.html.erb
format.json { render json: #community_topic }
end
end
models/community_topic.rb
acts_as_commentable
views/community_topics/show.html.erb
<%= render 'comments/form' %>
views/comments/_form.html.erb
<div class="field">
<%= f.label :comment %><br />
<%= f.text_area :comment %>
<%= f.hidden_field :commentable_id %>
<%= f.hidden_field :commentable_type %>
</div>
I found the answer.
I had to use comment_threads instead of comments as long as I was using 'acts_as_commentable_with_threading'
I have a admin section and inside the admin i have, Finalist and Images.
Im using, ruby 1.8.7-p249 and Rails 3.1.2
# model image.rb
class Admin::Image < ActiveRecord::Base
belongs_to :finalist
...
end
# model finalist.rb
class Admin::Image < ActiveRecord::Base
has_many :images
...
end
My ImagesController:
def new
#admin_finalist = Admin::Finalist.find(params[:finalist_id])
#admin_image = #admin_finalist.images.build
respond_to do |format|
format.html # new.html.erb
format.json { render :json => #admin_image }
end
end
def edit
#admin_finalist = Admin::Finalist.find(params[:finalist_id])
#admin_image = #admin_finalist.images.find(params[:id])
end
def create
#admin_finalist = Admin::Finalist.find(params[:finalist_id])
#admin_image = #admin_finalist.images.new(params[:admin_image])
respond_to do |format|
if #admin_image.save
format.html { redirect_to admin_finalist_images_path(#admin_finalist) }
format.json { render :json => #admin_image, :status => :created, :location => #admin_image }
else
format.html { render :action => "new" }
format.json { render :json => #admin_image.errors, :status => :unprocessable_entity }
end
end
end
def update
#admin_finalist = Admin::Finalist.find(params[:finalist_id])
#admin_image = #admin_finalist.images.find(params[:id])
respond_to do |format|
if #admin_image.update_attributes(params[:admin_image])
format.html { redirect_to admin_finalist_images_path(#admin_finalist) }
format.json { head :ok }
else
format.html { render :action => "edit" }
format.json { render :json => #admin_image.errors, :status => :unprocessable_entity }
end
end
end
And my Images _form.html.erb:
<%= form_for([#admin_finalist, #admin_image]) do |f| %>
<% if #admin_image.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#admin_image.errors.count, "error") %> prohibited this admin_image from being saved:</h2>
<ul>
<% #admin_image.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :file %>
<%= f.file_field :file %>
</div>
<%- unless #admin_image.new_record? || !#admin_image.file? -%>
<div class="field">
<%= f.label :remove_file, "Remover?" %>
<%= f.check_box :remove_file %>
</div>
<%- end -%>
<div class="field">
<%= f.label :url %>
<%= f.text_field :url, :placeholder => "http://" %>
</div>
<div class="field">
<%= f.label :title %>
<%= f.text_field :title %>
</div>
<div class="actions">
<%= image_submit_tag("button/save.png") %>
<%= link_to image_tag("button/back.png"), admin_finalist_images_path %>
</div>
<% end %>
Everything seems perfect, but im getting this error when im trying to add an image to finalist at admin/finalists/1/images/new.
Showing .../app/views/admin/images/_form.html.erb where line #5 raised:
undefined method `admin_finalist_admin_images_path' for #<#<Class:0x102da0068>:0x102d9a870>
So, i tryed to tell rails to use a particular url:
<%= form_for([#admin_finalist, #admin_image], :url => admin_finalist_image_path(#admin_finalist.id, #admin_image)) do |f| %>
Saddly, this work only for editing. When i try to edit i get this error message:
No route matches {:controller=>"admin/images", :finalist_id=>1, :id=>nil, :action=>"show"}
And if i wanna create i need to do:
<%= form_for([#admin_finalist, #admin_image], :url => admin_finalist_images_path) do |f| %>
And if i try to edit i get this message:
No route matches [PUT] "/admin/finalists/1/images"
I dont know what to do... I tried everything without success, if anyone can help me would be much appreciated.
EDIT
The problem was that my models was namespaced. So, i rewrite all the app to fix this, and thats running normally.
[]`s
I'm trying to create an associated form for Profiles but for some reason when I hit the submit button, I'm getting a NoMethodError which doesn't make sense to me as my code is exactly the same as a tutorial I'm following... unless the tutorial is outdated..
def create
#user = User.find(params[:user_id])
#profile = #user.profiles.create(params[:profile])
redirect_to user_path(#user)
end
Anyone know why I'm getting the noname errors?
The form that belongs to the controller is below:
https://github.com/imjp/SuperModel/blob/master/app/views/users/show.html.erb
EDIT 1: Fixed! The following code isn't displaying the profile data at http://localhost:3000/users/2 (which is profile#show) though: <%= #user.profile.first_name %>
Here's my current profiles#show
def show
#user = User.find(params[:user_id])
#profile = #user.profile.find(params[:id])
end
EDIT 2: I've updated my github repository at https://github.com/imjp/SuperModel
why #user.profiles? try #user.profile (singular)
You're getting undefined method 'first_name' for nil:NilClass because a User with that id could not be found. You're probably sending a wrong param or something. How does a URL for your show action look like?
edit:
change your create method in users_controller.rb to this
def create
#user = User.new(params[:user])
#user.build_profile
respond_to do |format|
if #user.save
format.html { redirect_to #user, notice: 'User was successfully created.' }
format.json { render json: #user, status: :created, location: #user }
else
format.html { render action: "new" }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
After you've changed this, change your form in app/views/users/show.html.erb to this
<h3>Add Profile</h3>
<%= form_for([#user, #user.profile]) do |f| %>
<div class="field">
<%= f.label :first_name %><br />
<%= f.text_field :first_name %>
</div>
<div class="field">
<%= f.label :last_name %><br />
<%= f.text_field :last_name %>
</div>
<div class="field">
<%= f.label :picture %><br />
<%= f.text_field :picture %>
</div>
<div class="field">
<%= f.radio_button(:sex, "male") %>
<%= f.label(:sex, "Male") %>
<%= f.radio_button(:sex, "female") %>
<%= f.label(:sex, "Female") %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
and it will work. Your user-profile association was not built.
I am having problems trying to set symbol values in a form view. My view has a couple instance variables being used, #task and #team, #team is the one im having issues with. Tasks have a :team value that needs to be set. In this view #team holds a value, but when I hit the "Create" button and make a post, the #team value is lost, and #task contains no team value.
Here is the view I'm dealing with:
Note: the ":team => #task.team" line doesn't work
<% form_for(#task) do |f| %>
<%= f.error_messages %>
<% #task.team = Team.find(#team) %>
<p><%= #task.team.title%></p>
<p>
<%= f.label :title %><br />
<%= f.text_field :title %>
</p>
<p>
<%= f.label :hours %><br />
<%= f.text_field :hours %>
</p>
<p>
<%= f.label :team %><br />
<% :team => #task.team %>
</p>
<p>
<%= f.submit 'Create'%>
</p>
<% end %>
The Post method that gets called on Create:
def create
#task = Task.new(params[:task])
respond_to do |format|
if #task.save
format.html { redirect_to(#task, :notice => 'Task was successfully created.') }
format.xml { render :xml => #task, :status => :created, :location => #task }
else
format.html { render :action => "new" }
format.xml { render :xml => #task.errors, :status => :unprocessable_entity }
end
end
end
#Jordinl is right when he mentions that you could use a hidden form field. You can also automatically scope the task to the team in the controller by doing something like
#team = Team.find(params[:team])
and then
#team.tasks << Task.new(params[:task])
You'll need to have a has_many association set up in the team model for tasks
has_many :tasks
for this to work. Each task will also need the team id as well but it sounds like you already have that.
Why don't you set it as a hidden field?
<%= f.hidden_field :team, :value => #task.team %>