My problem is that when I want to render the new action after an error in the create action, it's render without the styles for that action.
This are the new action and create action from the same controller:
# GET /users/new
def new
#user = User.new
render layout: 'application'
respond_to do |format|
format.html{}
end
end
# POST /users
# POST /users.json
def create
#user = User.new(user_params)
#role = Role.new
#role.email = #user.email
#role.tipo = "user"
respond_to do |format|
if #role.save
#Not relevant
else
format.html { render :new }
format.json { render json: {:estado => "false"}, status: :unprocessable_entity }
end
end
end
One thing that I detected is that when I submit the form from the new action and it has and error, then the url is /users. Shouldn't it be /users/new?
That the URL is /users is standard in the rails framework. That is the POST #create route which includes the error_messages.
The problem is this part in your 'new' action:
render layout: 'application'
A solution can be to add into your 'create' action:
render :new, :layout => 'application'
instead of just render :new.
So, use this instead:
format.html { render :new, :layout => 'application' }
It will render your layouts/application.
Related
I have a rails app with a page for a user to edit their own profile
app/views/manage_users/edit.html.erb and app/views/manage_users/new.html.erb contain:
<%= render 'form' %>
app/views/manage_users/_formt.html.erb contains:
<%= form_for(#user, :as => :user, :url => {:action => #form_action, :id => #user.id}) do |f| %>
When I fire up the page http://localhost:3000/manage_users/2/edit it shows me a typical form to edit a user object's data. If i blank out the email address http://snag.gy/atnmV.jpg and submit the form, I get an error that I would expect http://snag.gy/NRfwn.jpg and the url is now http://localhost:3000/manage_users/2:
Started PUT "/manage_users/2" for 127.0.0.1 at 2014-01-25 21:01:45 -0600
Processing by ManageUsersController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"B44/1b5m8usyAfe0hzLHNyjk/7Fpn5iEu3u6wGJMGL0=", "user"=>{"user_details_attributes"=>{"first_name"=>"Jeff", "last_name"=>"Smith", "id"=>"2"}, "email"=>"", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}, "button"=>"", "id"=>"2"}
If i put the email address back in and submit the form, the url now points to http://localhost:3000/manage_users?id=2 and I get the error No route matches [PUT] "/manage_users"
Why is it doing this and how can I fix it. If i just go to the initial page to edit a user and save it right away (instead of blanking out the email), everything works just fine.
app/controllers/manage_users_controller.rb
class ManageUsersController < ApplicationController
before_filter :admin_only, :except => [:edit, :update]
# GET /manage_users
# GET /manage_users.json
def index
#users = User.active
respond_to do |format|
format.html # index.html.erb
format.json { render json: #users }
end
end
# GET /manage_users/new
# GET /manage_users/new.json
def new
#user = User.new
#user.build_user_details
#form_action = 'create'
respond_to do |format|
format.html # new.html.erb
format.json { render json: #user }
end
end
# GET /manage_users/1/edit
def edit
#user = User.find(params[:id])
#permissions_disabled = params[:id].to_i == current_user.id.to_i
#p #permissions_disabled
able_to_edit_profile?
session[:return_to] ||= request.referer
#form_action = 'update'
end
# POST /manage_users
# POST /manage_users.json
def create
#user = User.new(params[:user])
#p "in create"
respond_to do |format|
if #user.save
format.html {
flash[:notice] = 'User was successfully created.'
redirect_to(:action => :index)
}
format.json { render json: #user, status: :created, location: #user }
else
format.html { render action: "new", notice: 'Error creating user.' }
format.json { render json: #user, status: :unprocessable_entity }
end
end
end
# PUT /manage_users/1
def update
#user = User.find(params[:id])
able_to_edit_profile?
# required for settings form to submit when password is left blank
if params[:user][:password].blank?
params[:user].delete("password")
params[:user].delete("password_confirmation")
end
respond_to do |format|
if #user.update_attributes(params[:user])
#user.save
# sign the user in with their new password so it doesn't redirect to the login screen
if current_user == #user
sign_in #user, :bypass => true
end
format.html {
p "in success format.html"
flash[:notice] = 'User was successfully updated.'
redirect_to session.delete(:return_to)
}
else
p "in else"
format.html { render action: "edit", notice: 'Error updating user.' }
#format.html {
#flash[:notice] = #user.errors
# redirect_to edit_manage_user_path(#user)
#}
end
end
end
private
# If the user is not an admin and trying to edit someone else's profile, redirect them
def able_to_edit_profile?
if !current_user.try(:admin?) && current_user.id != #user.id
flash[:alert] = "That area is for administrators only."
redirect_to :root
end
end
end
EDIT
So by changing this:
format.html { render action: "edit", notice: 'Error updating user.' }
to:
format.html {
flash[:notice] = #user.errors.full_messages.to_sentence
redirect_to edit_manage_user_path(#user)
}
I'm able to circumvent the issue. I'm still curious as to why rendering 'edit' doesn't work after a failed update.
When you render the edit action from the update method (in the failure path), it doesn't run the edit method, so #form_action is nil when you render the form. You'll need to address that.
I usually don't need to set the url, only in rare cases do I. You may be able to leave that out and let rails take care of the url and HTTP method.
Tearing my hair out here. I have a brand model, this has_many projects and the projects belong_to the brand. I'm trying to create projects inside the brand but I'm running into the following error:
undefined method `projects_path'
Everything seems to be in order. Some of my code can be found below:
Routes
resources :brands do
resources :projects do
resources :ideas
end
end
Brands
<%= link_to 'Create New Project', new_brand_project_path(#brand) %>
The routing is working, as the link I'm sent to is brand/brand_id/projects/new - but this is where I get the error I mentioned earlier.
Update - The original problem was fixed, now when I save the project I'm getting the same error, but this time something is wrong with 'create'...
class ProjectsController < ApplicationController
# GET /projects
# GET /projects.json
def index
#projects = Project.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #projects }
end
end
# GET /projects/1
# GET /projects/1.json
def show
#project = Project.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #project }
end
end
# GET /projects/new
# GET /projects/new.json
def new
#brand = Brand.find(params[:brand_id])
#project = Project.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #project }
end
end
# GET /projects/1/edit
def edit
#project = Project.find(params[:id])
end
# POST /projects
# POST /projects.json
def create
#project = Project.new(params[:project])
respond_to do |format|
if #project.save
format.html { redirect_to #project, notice: 'Project was successfully created.' }
format.json { render json: #project, status: :created, location: #project }
else
format.html { render action: "new" }
format.json { render json: #project.errors, status: :unprocessable_entity }
end
end
end
Add #brand = Brand.find(params[:brand_id]) to all your methods.
Remember the view comes back to the controller each time and can't remember what was set last time. The new method builds you the html form, but the create method is used to take the data and create the new record. But the create method doesn't know what you did in new, it can only work from the parameter data it was given.
(I've broken out the 2nd question that originally was part of this post into a separate post)
I am creating a product landing page with Rails in which users can enter their email address to be notified when the product launches. (Yes, there are services/gems etc that could do this for me, but I am new to programming and want to build it myself to learn rails.)
On submit of the form, if there are errors, the app currently redirects to '/invites' I would like to instead display error messages on the same page/URL as the original form? (In my case, the form is located at root while the error messages are displaying at '/invites')
I have read the Rails Guide on Routes and numerous stackoverflow posts on handling form errors nothing I've found seems to answer the question I have.
Update: Based on the reply from #rovermicrover I would like to clarify that, while I'm open to an Ajax solution, I'm fine with a page refresh that displays the error message. (I was not able to get the recommendation by #rovermicrover to function as desired - see my response to that solution below for more details.)
What I did:
Invite model:
class Invite < ActiveRecord::Base
attr_accessible :email
validates :email, :presence => {:message => "Please enter an email address."}
end
My routes file:
SuggestionBoxApp::Application.routes.draw do
root to: 'invites#new'
resources :invites
end
This is what I have in the Invites controller (I've only included the actions I'm referencing: new, create, show - it's basically the default of what Rails might generate):
class InvitesController < ApplicationController
def show
#invite = Invite.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #invite }
end
end
def new
#invite = Invite.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #invite }
end
end
def create
#invite = Invite.new(params[:invite])
respond_to do |format|
if #invite.save
format.html { redirect_to #invite }
format.json { render json: #invite, status: :created, location: #invite }
else
format.html { render action: "new" }
format.json { render json: #invite.errors, status: :unprocessable_entity }
end
end
end
end
Please let me know if there is any additional info I can provide in helping to answer this question. Thanks!
Make the form 'remote'
form_for #invite, :remote => true
....
Then in the controller
def create
#invite = Invite.new(params[:invite])
respond_to do |format|
if #invite.save
format.html { redirect_to #invite }
format.js { render :action => 'create_suc'}
else
format.html { render action: "new" }
format.js { render :action => 'create_fail' }
end
end
end
/invites/create_suc.js.erb
$('#errors').remove()
$('#new_invite').prepend("<div class='Thanks'>Thanks for signing up</div>")
$('#new_invite').hide("")
/invites/create_fail.js.erb
$('#new_invite').html('<%= escape_javascript render("form", :invite => #invite) %>');
Forms is a partial with your.... form in it, and also the handling of all errors on #invite.
There is a way to do this without resorting the making the form submit "remote", from a pure Ruby on Rails perspective. However, you can do this only if the browser has enabled cookies.
The idea is to save the form data in the session information in case of an error.
Just remember to delete the session data in case of success.
def new
#invite = Invite.new(session[:invite])
respond_to do |format|
format.html # new.html.erb
format.json { render json: #invite }
end
end
def create
#invite = Invite.new(params[:invite])
respond_to do |format|
if #invite.save
session.delete(:invite)
format.html { redirect_to #invite }
format.json { render json: #invite, status: :created, location: #invite }
else
session[:invite] = params[:invite]
format.html { render action: "new" }
format.json { render json: #invite.errors, status: :unprocessable_entity }
end
end
end
How does rails know how to map to each function in the controller if the routes.rb file only specifies:
resources :users
but inside the UsersController you have
class UsersController < ApplicationController
# GET /users
# GET /users.json
def index
#users = User.all
respond_to do |format|
format.html # index.html.erb
format.json { render :json => #users }
end
end
# GET /users/1
# GET /users/1.json
def show
#user = User.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render :json => #user }
end
end
# GET /users/new
# GET /users/new.json
def new
#user = User.new
respond_to do |format|
format.html # new.html.erb
format.json { render :json => #user }
end
end
# GET /users/1/edit
def edit
#user = User.find(params[:id])
end
# POST /users
# POST /users.json
def create
#user = User.new(params[:user])
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
# PUT /users/1
# PUT /users/1.json
def update
#user = User.find(params[:id])
respond_to do |format|
if #user.update_attributes(params[:user])
format.html { redirect_to #user, :notice => 'User was successfully updated.' }
format.json { head :no_content }
else
format.html { render :action => "edit" }
format.json { render :json => #user.errors, :status => :unprocessable_entity }
end
end
end
# DELETE /users/1
# DELETE /users/1.json
def destroy
#user = User.find(params[:id])
#user.destroy
respond_to do |format|
format.html { redirect_to users_url }
format.json { head :no_content }
end
end
end
How does rails determine that for instance the index function maps to GET/users while the create function maps to POST/users?
How does resources :users even know to map to the UsersController?
Rails is based around the 'convention over configuration' paradigm.
As such, the "resources :users" line indicates that all the standard CRUD methods are supported by the corresponding UsersController <-- the 'Users' prefix matches to the Controller, Model etc.
Please check the rails routes guide: http://guides.rubyonrails.org/routing.html
And to see in practice what the routes declaration does issue this command in your project directory:
rake routes
Also as mentioned before, stick with conventions and remember that rails is a very opinionated piece of software.
I've come across a really strange error. I've installed 'Blogit' and am trying to add on a few bits and pieces. I'm encountering a strange error when I submit a new entry:
Template is missing
Missing template blogit/posts/create, blogit/application/create, application/create with
{:locale=>[:en], :formats=>[:html], :handlers=>[:erb, :builder, :coffee]}. Searched in: *
"/Users/James/Documents/Websites/Backpack Bug/app/views" * "/Users/James/.rvm/gems/ruby-
1.9.3-p0/gems/blogit-0.4.8/app/views" * "/Users/James/.rvm/gems/ruby-1.9.3-
p0/gems/kaminari-0.14.1/app/views" * "/Users/James/.rvm/gems/ruby-1.9.3-p0/gems/devise-
2.1.2/app/views"
I have a feeling this is to do with my routing. Here is routes.rb
appname::Application.routes.draw do
root :to => 'locations#index'
devise_for :users
resources :locations do
collection do
get 'location'
end
end
mount Blogit::Engine => "/blog", :as => "blog"
end
Here is the posts controller:
module Blogit
class PostsController < ApplicationController
unless blogit_conf.include_admin_actions
before_filter :raise_404, except: [:index, :show, :tagged]
end
blogit_authenticate(except: [:index, :show, :tagged])
blogit_cacher(:index, :show, :tagged)
blogit_sweeper(:create, :update, :destroy)
def index
respond_to do |format|
format.xml {
#posts = Post.order('created_at DESC')
}
format.html {
#posts = Post.for_index(params[:page])
}
format.rss {
#posts = Post.order('created_at DESC')
}
end
end
def show
#post = Post.find(params[:id])
#comment = #post.comments.new
end
def tagged
#posts = Post.for_index(params[:page]).tagged_with(params[:tag])
render :index
end
def location
#georesult = Geocoder.search(params[:location])
respond_to do |format|
format.html {render :layout=>false}# venues.html.erb
end
end
def new
#post = current_blogger.blog_posts.new(params[:post])
#location = #post.locations.build
end
def edit
#post = current_blogger.blog_posts.find(params[:id])
#location = #post.locations.new
end
def create
#post = current_blogger.blog_posts.new(params[:post])
respond_to do |format|
if #post.save
format.html { redirect_to #post, :method => :get, notice: 'Blog post was successfully created.' }
format.json { render json: #post, status: :created, location: #post }
else
format.html { render action: "new" }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
def update
#post = current_blogger.blog_posts.find(params[:id])
if #post.update_attributes(params[:post])
redirect_to #post, notice: 'Blog post was successfully updated.'
else
render action: "edit"
end
end
def destroy
#post = current_blogger.blog_posts.find(params[:id])
#post.destroy
redirect_to posts_url, notice: "Blog post was successfully destroyed."
end
private
def raise_404
# Don't include admin actions if include_admin_actions is false
render file: "#{Rails.root}/public/404.html", status: :not_found, layout: false
end
end
end
All I've changed from the source so far is, I've basically created a multipart form which allows searches for locations and submits them to a locations table in the same post action. Not sure if this has anything to do with it. I can post up all this code but it's pretty lengthy. Let me know if you think this would be useful too.
Thanks a lot for all your help! Frankly, I'm stumped.
James
Just a hunch: see if your location action is getting called. I just experienced a slightly different error where any calls to redirect_to in my controller were causing my location method in the same controller to get called. (Putting a raise at the beginning of the location method will quickly let you know.)
I haven't tried investigation exactly why this was happening, but renaming my location action fixed this (obviously, this required changing any other code that referenced that endpoint, like AJAX requests in my JavaScript). Rails magic, no doubt.