Allow method to accept an :id param - ruby-on-rails

I have created a method called verify in a controller (events_controller.rb), and I want to allow that page (verify.html.erb) to accept an object (#event), and show of that objects parameters. I'm creating a show page in essence, but I need to build some special logic into this page that I don't want to build into the show page. I have created the route, but I still get an error when I tell it to find an Event by params[:id]. The actual url it is going to is /verify.(event :id) and I believe it should be routing to events/verify/(event :id).
My error
Couldn't find Event without an ID.
routes.rb
get "verify", to: 'events#verify'
resources :events
events_controller.rb
def verify
#event = Event.find(params[:id])
respond_to do |format|
format.html # verify.html.erb
format.json { render json: #event }
end
end
Thanks Stack!

get "verify/:id", to: 'events#verify', as: "verify"
in browser go to url for example:
localhost:3000/verify/1

Related

render method url dosen't match original url

Let's say i have a form which is at:
/categories/new
When form input is invalid I call render. Classic example:
def create
#category = Category.new(category_params)
if #category.save
flash[:success] = 'Category successfully created.'
redirect_to #category
else
render 'new'
end
end
My question is, why site path after call to render is just:
/categories
and not:
/categories/new
As I understand 'new' form should be rendered on the same page and those two paths clearly aren't the same.
As commenters suggested here is additional info:
related routes:
resources :categories do
resources :topics, name_prefix: 'category_',
except: [:index, :show, :edit, :update, :destroy]
end
category new action:
def new
#category = Category.new
end
Don't confuse what the url shows with what is actually rendered.
Short Answer
When you initially input your form you are actually doing a POST to /categories. This of course maps to the create action in your controller which when failing validation causes the new form to render - it isn't a redirect so the url won't change - the url remains the same as it did when you entered the action.
Detailed Explanation
When you invoke /categories/new you are actually being routed to the new action on the categories controller.
Your new action then sets any instance variables, for example #category, and rails will render the new.html.erb which contains your new category form.
When you submit the form it actually is doing a http POST to /categories, which routes to the create action of your categories controller. That url and http method is a result of what is generated from the form_for helper:
<%= form_for #category do |f| %>
This is why the url changes from /categories/new to /categories
Now the create action if it fails the validation simply renders the new form - it is not redirecting anywhere - the url remains unchanged from what it was when it entered this action - meaning, it remains as /categories.
Don't confuse the change in url with a redirection it's just that the form is posting to a different url than /categories/new, and the change in url is actually just a cosmetic issue.
Now if it is a concern to you, you can change the routing to something like the following:
resources :categories, except: [:create, :new]
post 'new_category' => 'categories#create'
get 'new_category' => 'categories#new'
This is mapping the POST and GET http methods to /new_category so the url appears the same for the new and create action invocations. Note you do need to change the url in the form_for helper to use this new route:
<%= form_for #category, url: 'new_category' do |f| %>

URL create and new in Rails

I created a new Rails project. After all, I have a question that I cannot find anywhere or answer by myself so I need your help.
When you create a new object (like Person, Book), you need 2 action: NEW and CREATE.
When I create new, I have link: localhost:3000/admin/books/new
And then when I create fails it will return ERROR MESSAGE anf this link: localhost:3000/admin/books/create
If I click in url and `ENTER`. It will wrong.
I'm trying to use redirect_to or render if creation is failed. But nothing happen, sometimes it go to new page but it don't show error message.
I think is a rule in Rails. But I still want to ask that anyone have any idea to resolve this problem??? Go tonewlink witherror messageif they're failed
More details: I'm using Typus gem to create view for admin. So I can't find Routes file. I run rake routes and get:
GET /admin/books/(:/action(/:id)) (.:format)
POST /admin/books/(:/action(/:id)) (.:format)
PATCH /admin/books/(:/action(/:id)) (.:format)
DELETE /admin/books/(:/action(/:id)) (.:format)
And controller when create book:
if result
format.html { redirect_on_success }
format.json { render json: #item }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: #item.errors, status: :unprocessable_entity }
end
Thanks for your helping :)
That is the normal way that Rails works. To understand what is happening, you need to understand what is HTTP verbs and how they works.
When you visit http://localhost:3000/book/new, you are making a request to the server to get (GET Verb) some information. In this case, a form to submit a new Book.
When You click submit, you are Sending (POST verb) data to the Server. On Rails, the link http://localhost:3000/book/create is available only by POST request. That is why, when you visit this link directly, it says that the route was not found.
This line:
# ...
else
format.html { render :new, status: :unprocessable_entity
end
means that, if something wrong happens, it need to render the view of new action again without redirect. This way you are able to find the errors on the object you are trying to save.
If you redirect, you will lose the actual (at the create stage) object. New object without data and error will be created on the new action:
def new
#book = Book.new
end
For this reason you are unable to access the error mensagens when you redirect. Only you can do on redirection, is setting a flash message:
if #book.save
redirect_to #book
else
flash[:error] = "An error occurred while saving Book."
redirect_to :new
end
2 resources that will hep you with that:
https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Request_methods
http://guides.rubyonrails.org/routing.html#crud-verbs-and-actions
On your rake routes, you could notice that it is prefixed with admin.
GET /admin/books/(:/action(/:id)) (.:format)
POST /admin/books/(:/action(/:id)) (.:format)
PATCH /admin/books/(:/action(/:id)) (.:format)
DELETE /admin/books/(:/action(/:id)) (.:format)
Did you try it to prefixed with admin/books/new? And admin/books/create? Then notice your url: you use only book since on your routes it is books.
Try:
http://localhost:3000/admin/books/new
http://localhost:3000/admin/books/create
You shouldn't be getting that error, there (by default) is no /create path, especially with a GET verb.
Whilst you can create your own /create path, your functionality is conventional:
#config/routes.rb
scope :admin do
resources :books, :people, only: [:new, :create] #-> url.com/admin/books/new
end
#app/controllers/books_controller.rb
class BooksController < ApplicationController
respond_to :json, :html, only: :create #-> needs responders gem
def new
#book = Book.new
end
def create
#book = Book.new book_params
respond_with #book if #book.save
end
end
The above is the standardized (working) way to achieve what you want.
--
As per the routes, there is no /create path:
POST /photos photos#create create a new photo

Conditional routing for nested resource in Rails controller #edit action, depending on where request came from

I have a Foo resource that has_many Bars. I'm using nested resources for a limited number of actions, but otherwise prefer to keep my routing for bars shallow. There are two ways to navigate to the edit view for the Bar object - either from the nested path that includes foo, or from the shallower bar path that isn't nested inside foo. For example, a user might click the edit button from the page at /foos/[:foo_id]/bar/[:bar_id]; or from /bars/[:bar_id].
In the first case, I want the controller to redirect the user back to the parent foo page: /foos/[:foo_id] after the record is updated. In the second case, I want it to redirect to the index view for bars: /bars. I believe I need some sort of conditional in the #edit action in the bars controller that will tell Rails where to go after #update executes.
# config/routes.rb
resources :foos do
resources :bars, only: [:new, :edit]
end
resources :bars
# bin/rake routes:
foo_bars POST /foos/:foo_id/bars(.:format) bars#create
new_foo_bar GET /foos/:foo_id/bars/new(.:format) bars#new
edit_foo_bar GET /foos/:foo_id/bars/:id/edit(.:format) bars#edit
bars GET /bars(.:format) bars#index
POST /bars(.:format) bars#create
new_bar GET /bars/new(.:format) bars#new
edit_bar GET /bars/:id/edit(.:format) bars#edit
bar GET /bars/:id(.:format) bars#show
PATCH /bars/:id(.:format) bars#update
PUT /bars/:id(.:format) bars#update
DELETE /bars/:id(.:format) bars#destroy
The controller for bars:
# app/controllers/bar_controller.rb
def edit
#bar = bar.find(params[:id])
#foo = #bar.foo
end
def update
#bar = bar.find(params[:id])
#foo = #bar.foo
respond_to do |format|
if #bar.update_attributes(bar_params)
format.html { redirect_to #foo, notice: "bar successfully updated" }
else
format.html { render action: "edit" }
end
end
end
I'm trying to change the redirect_to #foo line in the #update action so there is conditional logic that switches out #foo for #bars depending on where the #edit action was initiated. I've tried something like the following to test whether params[:foo] is present when the #edit action is called, setting an instance variable for the redirect.
def edit
if params[:foo]
#redirect_page = #foo
else
#redirect_page = #bars
end
#bar = bar.find(params[:id])
#foo = #bar.foo
end
def update
# code omitted...
format.html { redirect_to #redirect_page, notice: "bar successfully updated" }
# code omitted...
end
This doesn't work. Rails states cannot redirect to nil!. I've also tried something using a test based on URI(request.referer).path in the #edit action, without success.
I'm still not entirely clear how the Rails magic happens in the controller. I believe the #edit action is the proper place to define the conditional for the redirect (or through a method called in the #edit action), as that's where the controller will "see" the incoming request and know where it came from. But I can't quite figure out to capture that information, and pass it along to #update. Appreciate any guidance.
In your edit forms, add a hidden_field_tag:
<%= hidden_field_tag "route", request.env['PATH_INFO'] %>
Then in your controller, you can have an if statement and use a redirect_to based on what the params[:route] is.
I figured it out. The params[:route] method using request.env['PATH_INFO] wasn't working for me, because the 'PATH_INFO' variable in the form was providing the path handed off to the bars#update action, instead of the path where the bars#edit action was initiated.
After clicking "Edit" from the parent foo page at /foos/[:id] the params hash is:
>> params
=> {"controller"=>"bars", "action"=>"edit", "foo_id"=>"3786", "id"=>"16"}
There is no value for params[:route] when the form is first accessed - the hidden field is only added to the params hash after clicking "Update" in the edit form:
>> params[:route]
=> "/foos/3786/bars/16/edit"
This could work, but would require building logic to parse the route in order to redirect to /foos/[:foo_id]
It turned out to be simpler to use the Rails flash method to store the path for redirecting back to the source page. I did this by calling a custom method set_redirect_path in the BarsController, and calling it in bars#edit. This sets a value for the source in the flash, which is available in bars#update. Maybe there's a better/more conventional way to achieve this, but this seems to be a clean and simple way to do what I want.
# app/controllers/bars_controller.rb
def edit
set_redirect_path
#bar = bar.find(params[:id])
#foo = #bar.foo
end
def update
#bar = bar.find(params[:id])
#foo = #bar.foo
respond_to do |format|
if #bar.update_attributes(bar_params)
format.html { redirect_to flash[:source], notice: "bar successfully updated" }
format.xml { head :ok }
else
format.html { render action: "edit" }
format.xml { render xml: #bar.errors, status: :unprocessable_entity }
end
end
end
private
def set_redirect_path
flash[:source] = URI(request.referer).path
end
One advantage of this approach is I can now get rid of conditional logic in the shared partial app/views/bars/_list.html.haml that was required to determine whether clicking the "Edit" button should route to edit_foo_bar_path or to edit_bar_path (i.e. the former is chosen if #foo exists). Consequently, I can delete :edit for the nested resource :bars. Since the flash captures the incoming source of the request and stores it for reference in the #update action, all edit requests can use the same edit_bar_path, regardless of where they originate from. After update Rails redirects the user to the point where they initiated the #edit action.

How do I define a custom URL for a form confirmation page?

I am creating a basic 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 successful submit of the form, I would like to redirect to a custom '/thanks' page in which I thank users for their interest in the product (and also encourage them to complete a short survey.)
Currently, successful submits are displayed at "/invites/:id/" eg "invites/3" which I do not want since it exposes the number of invites that have been submitted. I would like to instead redirect all successful submits to a "/thanks" page.
I have attempted to research "rails custom URLs" but have not been able to find anything that works. The closest I was able to find was this Stackoverflow post on how to redirect with custom routes but did not fully understand the solution being recommended. I have also tried reading the Rails Guide on Routes but am new to this and did not see anything that I understood to allow for creating a custom URL.
I have placed my thanks message which I would like displayed on successful form submit in "views/invites/show.html.haml"
My Routes file
resources :invites
root :to => 'invites#new'
I tried inserting in routes.rb:
post "/:thanks" => "invites#show", :as => :thanks
But I don't know if this would work or how I would tell the controller to redirect to :thanks
My controller (basically vanilla rails, only relevant actions included here):
def show
#invite = Invite.find(params[:id])
show_path = "/thanks"
respond_to do |format|
format.html # show.html.erb
format.json { render json: #invite }
end
end
# GET /invites/new
# GET /invites/new.json
def new
#invite = Invite.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #invite }
end
end
# POST /invites
# POST /invites.json
def create
#invite = Invite.new(params[:invite])
respond_to do |format|
if #invite.save
format.html { redirect_to #invite }
#format.js { render :action => 'create_success' }
format.json { render json: #invite, status: :created, location: #invite }
else
format.html { render action: "new" }
#format.js { render :action => 'create_fail' }
format.json { render json: #invite.errors, status: :unprocessable_entity }
end
end
end
It would seem as if creating a standard URL for displaying a confirmation would be relatively straightforward. Any advice on how to achieve this would be appreciated.
I guess you want to redirect after your create action, which is executed when the form is submitted.
Just add redirect_to in the following way:
def create
#invite = Invite.new(params[:invite])
if #invite.save
...
redirect_to '/thanks'
else
...
redirect_to new_invite_path # if you want to return to the form submission page on error
end
end
I omitted some of the code for brevity.
In your routes add:
get '/thanks', to: "invites#thanks"
Add the thanks action to your invites controller:
def thanks
# something here if needed
end
And create a thanks.html.erb page in app/views/invites.
I would do get "/thanks" => "invites#thanks" in routes.rb and then add this in your controller:
def thanks
end
Then add a file app/views/invites/thanks.html.erb with your thank-you content.
You could create a route like this:
resources :invites do
collection do
get 'thanks'
end
end
This will also create a path helper called thanks_invites_path.
It will be at the invites/thanks path, but if you want it to be on/thanks, you could just do as Jason mentioned:
get "/thanks" => "invites#thanks", :as => :thanks
The as part will generate a helper to access that page: thanks_path.
You would need a extra action in the controller called thanks, and put whatever info you need inside, and also you will need a additional view called thanks.html.erb
Since you want everybody to go to that page after a successful submit, in your create action you would have:
format.html { redirect_to thanks_invites_path} (or thanks_path), what ever you choose, when you name the route you can check it with rake routes if it's okay, and whatever rake routes says, just add _path at the end.

How to modify the create & update method in RoR?

I know that the after the create or update methods is done, they have the method like this
respond_to do |format|
format.js
end
Since I change my form from remote form to non remote form, so I won't use the format.js anymore, I just want to refresh the page, after the user create/update a product, so I have this code:
respond_to do |format|
page.reload
end
But it don't work, so I try not to use respond_to do, I only have the page.reload. But it also show me the site like this:
http://localhost:3000/products/50
I just want to reload the page after I create/update, why I can't do it in this way?
The reload method reloads the browser's current location using JavaScript. I would suggest that you probably want to do a server-side redirect after creating or updating your resource. Something like one of these alternatives:
redirect_to product_path(#product) # Redirect to the 'show' page for the product
redirect_to products_path # Redirect to the products' index page
How can I assign the product_path? in routes.rb?
in routes.db you can either:
map.product 'products/:id', :controller => 'products', :action => 'view'
map.resources :product
map.resource :product
1) will give you product_path(123) and product_url
2) will give you product_path, new_product_path, edit_product_path and so on
HTH

Resources