Avoid index url after failing create - ruby-on-rails-3

When you create a User in rails through the create action, the url is changed to
http://myapplication.com/users with POST
before being redirected elsewhere. If validation fails, it appears that the above URL is retained. If you then refresh, you end up on the index page (as it's now a GET).
I would expect if validation was failed the url would remain as
http://myapplication.com/users/new
As i don't have an index page, this is causing me problems. Is there a way to resolve this please?

This depends on the logic in the respond_to block in your controller.
This is a typical example of the create action in users_controller.rb:
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
So if the save fails, the new action is rendered again.

In your UsersController, do like this:
def new
#user = User.new
end
def create
#user = User.new(params[:user])
if #user.save
redirect_to root_url # save success will return to root page
else
render 'new'
end
end

Related

Devise: after_sign_in_path_for(resource) not working

I am using devise for user sign up/in. But when user signs in from public accessible pages, devise redirects to root_path.
I tried to use this:
def after_sign_in_path_for(resource)
request.referrer
end
When user tries to sign in, it gives error 'not redirected properly'.
Can anybody tell how to do it?
I believe if I am right what you want to do is override the redirect when a user sign in is to change the following method inside controllers/devise/sessions_controller.rb If you haven't generated devises controllers you generate devise controller. Having done that you will want to have something like the following inside your devise/sessions_controller.rb
def create
self.resource = warden.authenticate!(auth_options)
set_flash_message(:notice, :signed_in) if is_navigational_format?
sign_in(resource_name, resource)
# respond_with resource, :location => after_sign_in_path_for(resource)
if current_user.role? :administrator
redirect_to dashboard_path
else
redirect_to rota_days_path
end
end
In the above example by default the sessions_controller - create method uses the following: # respond_with resource, :location => after_sign_in_path_for(resource) which I have commented out. By adding a if statement that checks if the current_users role is an administrator. If they then they are redirected to the dashboard page. If not then they are redirected to the rota page.
Alternatively the devise helpers state that you could also do something like:
def after_sign_in_path_for(resource)
stored_location_for(resource) ||
if resource.is_a?(User) && resource.can_publish?
publisher_url
else
super
end
end
Hope this helps.
Update
def create
#hospital_booking = HospitalBooking.new(params[:hospital_booking])
respond_to do |format|
if #hospital_booking.save
format.html { redirect_to :back, notice: 'Photographer Shift was successfully created.' }
format.json { render json: #hospital_booking, status: :created, location: #hospital_booking }
else
format.html { render action: 'new' }
format.json { render json: #hospital_booking.errors, status: :unprocessable_entity }
end
end
end
What happens here is when the hospital_booking is saved it redirects back to the issue page instead of redirecting to another page. Further reading here: api dock- redirect_to

Rails: Nested resource and specifying the "nester"

A company has many properties. A property has one company.
In my routes file I got:
resources :companies do
resources :property_managers
end
In the property_manager_controller, my create action looks like this (default scaffold implementation slightly modified to accommodate the company):
def create
#property_manager = PropertyManager.new(params[:property_manager])
#property_manager.company_id = params[:company_id]
respond_to do |format|
if #property_manager.save
format.html { redirect_to company_property_managers_path, notice: 'Property manager was successfully created.' }
format.json { render json: #property_manager, status: :created, location: #property_manager }
else
format.html { render action: "new" }
format.json { render json: #property_manager.errors, status: :unprocessable_entity }
end
end
end
Is there a way in which I do not have to explicitly set the company_id, since it is known within the context of the URL/route?
I guess you could do something like the following, not sure if it's better or not:
class PropertyManagersController < ApplicationController
before_filter :find_company
def new
#property_manager = #company.property_managers.build
end
def create
#property_manager = #company.property_managers.build(params[:property_manager])
respond_to do |format|
...
end
end
private
def find_company
#company ||= Company.find(params[:company_id])
end
end

Rails 3 No Route Matches Error

My application uses tickets and call_logs. I have these nested in each other, so that tickets can have many call_logs.
I am getting the error with [GET] "/call_logs"
I don't know what I am missing here.
I do have my routes nested in routes.rb
resources :tickets do
resources :call_logs
end
rake routes:
ticket_call_logs GET /tickets/:ticket_id/call_logs(.:format) call_logs#index
POST /tickets/:ticket_id/call_logs(.:format) call_logs#create
new_ticket_call_log GET /tickets/:ticket_id/call_logs/new(.:format) call_logs#new
edit_ticket_call_log GET /tickets/:ticket_id/call_logs/:id/edit(.:format) call_logs#edit
ticket_call_log GET /tickets/:ticket_id/call_logs/:id(.:format) call_logs#show
PUT /tickets/:ticket_id/call_logs/:id(.:format) call_logs#update
DELETE /tickets/:ticket_id/call_logs/:id(.:format) call_logs#destroy
tickets GET /tickets(.:format) tickets#index
POST /tickets(.:format) tickets#create
new_ticket GET /tickets/new(.:format) tickets#new
edit_ticket GET /tickets/:id/edit(.:format) tickets#edit
ticket GET /tickets/:id(.:format) tickets#show
PUT /tickets/:id(.:format) tickets#update
DELETE /tickets/:id(.:format) tickets#destroy
call_logs controller:
class CallLogsController < ApplicationController
before_filter :get_ticket
# GET /call_logs
# GET /call_logs.json
def index
#call_logs = #ticket.call_logs.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #call_logs }
end
# GET /call_logs/1
# GET /call_logs/1.json
def show
#call_log = #ticket.call_logs.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #call_log }
end
end
# GET /call_logs/new
# GET /call_logs/new.json
def new
#call_log = #ticket.call_logs.build
respond_to do |format|
format.html # new.html.erb
format.json { render json: #call_log }
end
end
# GET /call_logs/1/edit
def edit
#call_log = #ticket.call_logs.find(params[:id])
end
# POST /call_logs
# POST /call_logs.json
def create
#call_log = CallLog.new(params[:call_log])
respond_to do |format|
if #call_log.save
format.html { redirect_to ticket_call_logs_url(#ticket), notice: 'Call log was successfully created.' }
format.json { render json: #call_log, status: :created, location: #call_log }
else
format.html { render action: "new" }
format.json { render json: #call_log.errors, status: :unprocessable_entity }
end
end
end
# PUT /call_logs/1
# PUT /call_logs/1.json
def update
#call_log = #ticket.call_logs.find(params[:id])
respond_to do |format|
if #call_log.update_attributes(params[:call_log])
format.html { redirect_to ticket_call_logs_url(#ticket), notice: 'Call log was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #call_log.errors, status: :unprocessable_entity }
end
end
end
# DELETE /call_logs/1
# DELETE /call_logs/1.json
def destroy
#call_log = #ticket.call_log.find(params[:id])
#call_log.destroy
respond_to do |format|
format.html { redirect_to ticket_call_logs_path(#call_log)}
format.json { head :no_content }
end
end
end
end
private
def get_ticket
#ticket = Ticket.find(params[:ticket_id])
end
I believe I have an error in my url paths when directing to the call_log page, but I can't seem to find it. Any advice or tips would be appreciated, as I am a noob.
Thank you.
As you can see from the output of rake routes, You don't have a route that matches /call_logs. Since this is a nested resource route you have to prepend the tickets and ticket id: /tickets/<id>/call_logs.
Looks like you have done changes in routes.rb but not maintaining relation in Models. As rake routes say
ticket_call_logs GET /tickets/:ticket_id/call_logs(.:format)
Should be accessible by /ticket/id/call_logs , Now here "id" is ticket id. This will list all call logs for that particular ticket_id.

Can't create belongs_to association in controller

I have 2 models Users and Companies. (I'm using Devise for User)
User belongs to Company.
Company has many Users.
My User model includes an client_id column.
At the moment a User signs-up and is directed to the new_company_path where I'd like to create the relationship. (I'd prefer to keep this in 2 steps).
I know my code is wrong here in the companies_controller.rb — but it's where I'm at
def create
#user = current_user
#company = #user.Company.new(params[:company])
respond_to do |format|
if #company.save
format.html { redirect_to root_path, notice: 'Company was successfully created.' }
format.json { render json: #company, status: :created, location: #company }
else
format.html { render action: "new" }
format.json { render json: #company.errors, status: :unprocessable_entity }
end
end
Your problem lies within the line
#company = #user.Company.new(params[:company])
The association from user to company should not be accessed with a capital letter. To get the company associated with a user, you should call it like this:
#user.company
However, if there is no company associated then that method will return nil and you cannot call .new on nil so instead you need to call another method that Rails creates for you called build_company like this:
#company = #user.build_company(params[:company])
The last problem is that since it is the user that belongs to the company, the User instance needs to be updated with the newly created company_id and that will not happen if you only save the company. But when you use the build_company method, it will store the company instance in the association from User so if you call save on the user instead of the company it will create the company and link it to user, like this:
def create
#user = current_user
#user.build_company(params[:company])
respond_to do |format|
if #user.save
format.html { redirect_to root_path, notice: 'Company was successfully created.' }
format.json { render json: #user.company, status: :created, location: #user.company }
else
format.html { render action: "new" }
format.json { render json: #user.company.errors, status: :unprocessable_entity }
end
end
end
Your User model needs a company_id column. Then you can make a form to record that value wherever you like (i.e., on the new_company_path page).

Rails URL Access

I'm new to Ruby on Rails, so please pardon my ignorance. My issue is that I cannot access the Rails project from the browser. I assume it has something to do with the Rails config, but I am having no luck so far.
State of the Project
I have existing logic (controllers, models, migrations, ...).
If I leave index.html in place, I see the Rails welcome page because it is apparently rendered before Rails tries to parse the URL.
If I disable index.html, I get the 'Something went wrong' message which is generated by Rails.
If I have the httpd.conf document root set to 'my.domain.com/public' I get the Rails error, but if I have it set to 'my.domain.com/', I get an error served up by Apache instead. (So that seems to be correctly configured.)
The error logs show this error: File does not exist: /var/www/html/my.domain.com/zombies when I hit the URL.
My Environment
Rails 3.2.6
Ruby 1.9.3
Apache 2.2.3
CentOS
If it matters, I'm simply following the tutorial at Rails for Zombies 2.
Thanks in advance!
Reference
zombies_controller.rb
class ZombiesController < ApplicationController
# GET /zombies
# GET /zombies.json
def index
#zombies = Zombie.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #zombies }
end
end
# GET /zombies/1
# GET /zombies/1.json
def show
#zombie = Zombie.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #zombie }
end
end
# GET /zombies/new
# GET /zombies/new.json
def new
#zombie = Zombie.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #zombie }
end
end
# GET /zombies/1/edit
def edit
#zombie = Zombie.find(params[:id])
end
# POST /zombies
# POST /zombies.json
def create
#zombie = Zombie.new(params[:zombie])
respond_to do |format|
if #zombie.save
format.html { redirect_to #zombie, notice: 'Zombie was successfully created.' }
format.json { render json: #zombie, status: :created, location: #zombie }
else
format.html { render action: "new" }
format.json { render json: #zombie.errors, status: :unprocessable_entity }
end
end
end
# PUT /zombies/1
# PUT /zombies/1.json
def update
#zombie = Zombie.find(params[:id])
respond_to do |format|
if #zombie.update_attributes(params[:zombie])
format.html { redirect_to #zombie, notice: 'Zombie was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #zombie.errors, status: :unprocessable_entity }
end
end
end
# DELETE /zombies/1
# DELETE /zombies/1.json
def destroy
#zombie = Zombie.find(params[:id])
#zombie.destroy
respond_to do |format|
format.html { redirect_to zombies_url }
format.json { head :no_content }
end
end
end
Running rake assets:precompile seems to have fixed my issue. Thanks all.