I have two routes with new action for the same resource: individual_trainings :
new_backend_trainer_ind_training GET /backend/people/:id/trainers/:trainer_id/individual_trainings/new(.:format) backend/individual_trainings#new
new_backend_individual_training GET /backend/individual_trainings/new(.:format) backend/individual_trainings#new
How to specify what type of new should be rendered? If I use render :new, always redirect to second route. I don't want to use redirect_to, because I cannot handle errors for form. Any idea how to do this (I need render :new in create action). Maybe another new and create action?
Update:
I think there is a problem with simple_form in new_backend_trainer_ind_training :
= simple_form_for([:backend, #individual_training]) do |f|
it generates wrong url. Is it right?
If you want to do it this way (two routes for the same action) then you can pass path to simple_form:
= simple_form_for(#individual_training, url: new_backend_trainer_ind_training_path) do |f|
However, this is a bad approach to use different routes leading to the same action. If this is a different behavior, then you should create another controller with it's new/create action.
Related
In Rails, I'd like to skip the "new" method in a controller entirely and go directly to the create method. (I don't need any form data to be submitted, and just want to go directly to creating the object based on data from the currently logged in user.)
In rake routes, I don't see a prefix that allows me to link directly to the controller's create method, so I think I should link to the new method and have that redirect to the create action without accepting any input.
I tried doing this with the following:
def new
create
end
def create
#request = Request.new
#request.requestor_id = current_user.id
#request.status = "S1"
#request.save
respond_with(#request, :location => "/products/findexchanges")
end
When browsing the DB, I can see that this is calling the create action and is adding the record to the db, but after it is done it is redirecting me to new.html.erb rather than the location defined at the end of the create method.
A create action should be triggered by a POST, not GET, which is why there is no specific route for it.
Use button_to instead of link_to. I tried using link_to and even after specifying method: :post, action: :create, it still takes me to index using GET. After using button_to and passing params in ####_path, it directly went to the create method and added data to database. Although I am not sure its correct way or safe way to do this.
I have a controller show action which does some stuff and renders a view but due to some custom routing, I need a totally different action in a totally different controller to perform the same stuff and render the same view.
I don't really wish to duplicate the code. Is there somewhere I can put it and call it from both locations?
Edit:
I basically need to run the following from Collection#Show AND also from Gallery#SplitUrl:
#collection = Collection.find_by_id(params[:id])
if #collection.has_children?
#collections = #collection.children
else
redirect_to [#collection, :albums]
end
I cannot just redirect_to Collection#Show at the end of Gallery#SplitUrl as the redirect causes my custom URL's to be lost as it's a new request.
You could put the view content into a partial (/app/views/home/_example.html.erb) and then use the render "example" command in the HomeController.
The "some stuff" code you talk about could be put into a helper file /app/helpers/... to save you from duplicating code in the two separate controllers although it could depend on what the code is trying to do in the first place.
http://guides.rubyonrails.org/layouts_and_rendering.html
This might provide more information on the subject in general.
I think the simplest approach would be to add a route definition for your new url and map that to your existing controller's action.
Something like follows:
# config/routes.rb
# Existing resource
resources :foos
# The resource in question
resources :bars do
get :show, controller: 'foos', action: 'show', as: bar_foo_common_show
end
Note that this will give you /bar/:id, where id represents a bar resource. So in your foo#show action, your finder needs to be executed on appropriate class. This is when a few lines of hacky codes get added, for e.g. checking for request referer.
I think moving the common code to a function in possibly application_controller and calling that function from both show action would be cleaner approach, but based on my understanding you already have a similar scenario except for the common code in application_controller, and would like to try out a different approach!
So, I have search form, and search is avaliable obviously from any page.
I thought that it makes sense, that such action from application controller is placed in layouts/views folder.
But I just don't get- Rails doesn't see it. So I can't do this? How then should I provide action, avaliable from any page?
Code:
def tests_search
#tests=Test.test_search(params[:query])
respond_to do |format|
format.html
end
end
Route:
search_tests GET /search_tests(.:format) application#tests_search
Form:
<%= form_tag search_tests_path, {:id=>'test_search',:method => :get} do%>
Error:
Unknown action
The action 'tests_search' could not be found for ApplicationControllerr
You should create a new search controller. Use rails g controller search index which will create a search controller with a index action (you could also call the action something like result). Then add a search/_form.html.erb file in your search view folder, with the form:
<%= form_tag search_path, {:id=>'test_search',:method => :get} do |f| %>
and render this in your layout/application.html.erb where you want it to be:
<%= render "search/form" %>
This way you have a search form on any pages, that uses the SearchController to handle the search requests.
I would recommend using other controller to do this. It can be for example SearchController even if there will be only one method.
Notice that ApplicationController is controller that every other controller in application inherits from by default. So if it wouldn't be the case, it could make sense, but now every controller will inherit your test_search action, which is not desired.
If your search form will be a partial, then there is no difference whether this is in ApplicationController or in any other controller. You just have to point to right route.
Initially you have to explain yourself the flow. What you need is some partial which is rendered on all pages, and if a user adds some input to it and submits, he gets some output. Right? Good. So you start by creating a new partial somewhere in
app/views/shared/_search.html.erb
Then, you create your route in routes.rb to point to a controller's action. You don't have to place this in application_controller. Instead, create your search_controller.rb and create some action which responds to the form submission there.
Whenever you want to render your search form on other pages, you simply call render partial (more on that here) with something like
<%= render "shared/search" %>
This is good if you created the file above. Make sure your action exists and the name is correct, in your case it should be:
def test_search
...
end
Good luck.
I can't seem to figure out how to get my routes setup properly.
In my app, I have a view that lets site owners update their address information. The new and create actions are part of the signup process and are located in the signups_controller. The edit and update actions are in the settings_controller.
When the user goes into the settings area, he/she sees only the edit form. When filled out, the user is then returned to the same form with a flash message, or error message. Here is what the controller looks like:
class SettingsController < ApplicationController
def edit
#account = current_account
#account.companies.first
#account.companies.first.addresses.first
#account.companies.first.phones.first
end
def update
#account = current_account
if #account.update_attributes(params[:account])
redirect_to edit_setting_path
flash[:notice] = "Success!"
else
render :edit
end
end
end
In my routes, I simply have:
resources :settings
The link to this area of the site is a basic RESTful named linke, with the parameter options:
edit_setting_path(:id => current_account.id)
When the user arrives to this page, they see the following URL:
http://domainname.com/settings/1/edit
When they submit the form and get errors, the URL changes to:
http://domainname.com/settings/1
Why is the URL changing -- I'd rather it not? Is there a way to make it stay the same as the initial edit view? I've tried doing a redirect on a failed update, but then I don't get the error messages.
Any ideas?
To answer your "why" question: The URL is changing because it's reflecting the URL of the failed request - which in this case is a PUT request to that URL (/settings/1). You've submitted the form and the submission of that form (correctly) points to that URL. This is a result of the RESTful routes that the helper gives you. Since the logic in your action, falls through to the render :action, there is no redirect and the form simply re-renders on the page using the same data available in this action (which is why you can see the errors).
If you want to redirect back to the edit page, yes, you will lose the errors that have been set in the #account instance variable since the redirect will reset (re-query for) the account.
You could add a route that matches a PUT to /settings/1/edit and point it to your update action and change your form etc. In short, I wouldn't recommend this, but it should work.
completely untested but attemptable:
routes.rb
put "/settings/:id/edit", :to=>"settings#update", :as=>"update_setting"
resources :settings, :except=>:update
your form would also have to submit to the update_setting_path (which also means it's not reusable for a new object... ew)
First you should read up on The Rails Guides for Routing. They will help a lot to understand why its working like that.
Secondly, to accomplish what you are trying to do, you will need to add manual routes via the match call. You'll need something like this.
match '/settings/:id/edit' => "settings#edit"
I am building my first app with ROR and stumbled upon a couple of problems due to my understanding of the MVC
I have a page to add a new item, and this works fine, rails magically hooks it up to the items controller and somehow by magic it knows to look in the method 'new' as the page is called new.
But this layer is confusing me, as i need to now create a different version of new, same functionality but with a different look so to use a different layout to application.html.erb
So i attempt to create a copy of new.html.erb and create bookmarklet.html.erb - both contain exactly the same code: a link to a form. but of course bookmarklet will error on me because it does not have that link in the controller - how do i 'wire' up bookmarklet so that i can call the new method and so that it can behave in a similar way to the identical new.html.erb
Also, how can i tell the new bookmarklet.html.erb to ignore the application.html.erb and get its layout from another file?
thanks in advance
The magic happens in the routes. Rails uses something called RESTful routes, which is taking HTTP verbs and assigning standard actions to it. the new action is a GET request in HTTP speak, and if you are using scaffolding or following REST, will have the ruby call to build a new object in the controller, as an instance variable so you can use it in your view.
You have to tell rails routes that you want to BREAK this arrangement and to let /items/bookmarklet be used in the controller.
In your routes.rb file replace resources :items with
resources items do
member do
get 'bookmarklet'
end
end
In your controller put:
def bookmarklet
#item = Item.new
render :template => "bookmarklet", :layout => "different_layout" # or you can put this on the top of the controller, which is my style, but whatevs.
end
You should look into partials, if you are doing this as they clean up your code immensely.
A better way to think of things is to start with the controller instead of the view html.erb files. So each public method in your controller is effectively a page or action in the site. When you need a new action or page, add the method to the controller first. Then create the relevant view files.
So in your controller you'll need something like:
def bookmarklet
#item = Item.new(params[:item])
#item.save
render :template => "items/bookmarklet.html.erb", :layout => "different_layout.html.erb"
end
Normally you don't need to call render manually in the controller, but since you want a different layout than the default you need to specify it using render.