I have a non-standard method listByName in the OrdersController, as shown below.
class OrdersController < ApplicationController
def index
#orders=Order.all
end
def listByName(name)
#orders=Order.find_by(:name=>name)
render index
end
end
I want to create some links that can be routed to the OrdersController#listByName method.
<%= link_to 'listByName', listByName_path %>
My problem is how to construct the path in the html.erb pageļ¼ and how to write the router.rb?
Thanks
See the routing guide. Your question is answered in 1.1 and 1.2.
1.1 Connecting URLs to Code When your Rails application receives an incoming request for:
GET /patients/17
it asks the router to match it to a controller
action. If the first matching route is:
get '/patients/:id', to: 'patients#show'
the request is dispatched to
the patients controller's show action with { id: '17' } in params.
1.2 Generating Paths and URLs from Code You can also generate paths and URLs. If the route above is modified to be:
get '/patients/:id', to: 'patients#show', as: 'patient'
and your application contains this code in the controller:
#patient = Patient.find(17)
and this in the corresponding view:
<%= link_to 'Patient Record', patient_path(#patient) %> then the
router will generate the path /patients/17. This reduces the
brittleness of your view and makes your code easier to understand.
Note that the id does not need to be specified in the route helper.
Related
The problem is to pass Query params throuth the helper _path .
Example I know how to pass a normal param
edit_survey_path(#poll_module)
which generates
/survey/12 because of route /survey/:id
Which is right and okay for editing
However, I want to generate the following url for new_survey_path
/survey/new?pollModule=lgpd
so how should I write the
new_survey_path(????)
At the view's controller I have the #poll_module = 'lgpd'
Then I trided
new_survey_path(#poll_module)
new_survey_path({#poll_module})
new_survey_path({pollModule: #poll_module})
new_survey_path({:pollModule => #poll_module)
new_survey_path(:pollModule, {pollModule: #poll_module})
yes some are crazy, but it were things I have found on foruns
new_survey_path(#poll_module) generates
http://rubyenv:3000/surveys/new.lgpd?
that's because the route for edit is
#routes
new_survey GET /surveys/new(.:format) so is gets on the format
I want a query param
/surveys/new?pollModule=lgpd
because on the new survey I need to search the righ questions before answering the survey, and this question depende on the module
The problem it was not the _path helper, but the componet I was using on the view
if you use the button_to, it has already a parameter for parameters
{poll_module: 'teste123'} %>
doc ref ->
https://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#method-i-button_to
or if i you use the link_to it get the query by default
doc -ref->
https://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#method-i-link_to
Normally you pass a query param like this new_survey_path({key: "value1", key2: "value2"}). So the one version you have reported that you tried should have worked. Thats why i assume it could interfere with your routes. Can you try to isolate the problem and simply add the following to your project:
# routes.rb
resources :surveys, only: [:new]
# app/controllers/surveys_controller.rb
class SurveysController < ApplicationController
def new
#pollModule = params[:pollModule]
end
end
<!-- app/views/surveys/new.html.erb -->
<h1>New Survey</h1>
<p>poll module inserted as query param: <%= #pollModule %></p>
<%= link_to "testLink", new_survey_path(pollModule: "randomInput") %>
When you click on the "testLink" it should redirect you to the URL localhost:3000/surveys/new?pollModule=randomInput.
Also be sure that the route is at the top of your routes.rb file, since sometimes the ordering is what messes things up. Hope that helpes and let me know if it worked.
I'm creating a Rails application where there is a resource used as general settings for the whole website. I set everything as follows:
config/routes.rb
authenticate :user do
scope '/admin' do
resource :basics #This is my resource's name, put in singular
# ...
end
end
controllers/basics_controller.rb
private
# Use callbacks to share common setup or constraints between actions.
def set_basic
#basic = Basic.first
end
views/basics/_form.html.erb
<%= form_with(model: #basics, local: true) do |form| %>
Here is what rake routes shows about this resource:
new_basics GET /admin/basics/new(.:format) basics#new
edit_basics GET /admin/basics/edit(.:format) basics#edit
basics GET /admin/basics(.:format) basics#show
PATCH /admin/basics(.:format) basics#update
PUT /admin/basics(.:format) basics#update
DELETE /admin/basics(.:format) basics#destroy
POST /admin/basics(.:format) basics#create
I don't have any trouble making the form show up. However, when I submit it, I get the following error:
No route matches [POST] "/admin/basics/edit"
When I look at the HTML generated form, I can see that it passes "/admin/basics/edit" as an action while it should be just "/admin/basics" in my situation.
What should I do to make this work?
Thank you in advance
It looks like maybe you have the wrong instance variable passed to the form_with method? IIRC, Rails assumes the form action should be the same as the current path if the model argument is nil.
#basics is not defined (at least in the controller code you shared). Replacing it with #basic might work for edits (when Basic.first exists), but not create (if Basic.first doesn't exist).
You could try initializing #basic in your controller like this
def set_basic
#basic = Basic.first_or_initialize
end
Then pass it to form_with
<%= form_with(model: #basic, local: true) do |form| %>
i'v been trying to resolve this error for the past 5 hours and I'm gonna burn my computer if I can't solve this.
undefined method `pushes_path' for #<#:0x007f859d605250> this is the error code I'm getting but i don't understand why.
this is my index.html.erb file inside of the interaction
<%= simple_form_for #push do |f| %>
<%= f.input :payload, as: :text %>
<%= f.input :segment, as: :radio_buttons %>
<%= submit_tag "start the campaign" %>
<% end %>
and this is my interaction controller
class InteractionController < ApplicationController
def index
#push =Push.new
end
end
Push is my table in the database and i'll get the inputs and write them in the database to use them for later one.
and this is my routes file
devise_for :partners
get 'home/index'
get 'segmentation/index'
get 'interaction/index'
root to: "home#index"
i really don't know why its looking for pushes_path, what am i doing wrong?
form_for
The problem you have is that your form_for method is going to try and generate a route based off your #path object. And as such, if you don't have a path created for it, you'll receive the error you're getting:
:url- The URL the form is to be submitted to. This may be represented
in the same way as values passed to url_for or link_to. So for example
you may use a named route directly. When the model is represented by a
string or symbol, as in the example above, if the :url option is not
specified, by default the form will be sent back to the current url
(We will describe below an alternative resource-oriented usage of
form_for in which the URL does not need to be specified explicitly).
The bottom line is that as Rails is object orientated, its built around the assumption that you'll have routes set up to handle the creation of individual objects.
Every time you use form_for, Rails will attempt to construct your routes from your object -- so if you're trying to do the following, it will treat the routes as photo_path etc:
#app/views/pushes/new.html.erb
<%= form_for #push do |f| %>
...
<% end %>
--
Fixes
As #mandeep suggested, there are several fixes you can employ to get this to work:
Firstly, you can just create a route for your push objects:
#config/routes.rb
resources :pushes
Secondly, as you're using a different controller, you'll want to do the following:
#config/routes.rb
resources :interactions
#app/views/pushes/new.html.erb
<%= form_for #push, url: interaction_path do |f| %>
...
<% end %>
This will route your form submission to the interactions controller, rather than the pushes controller that you'll get by default!
Objects
Something to consider when creating Rails-based backends is the object-orientated nature of the framework.
By virtue of being built on Ruby, Rails is centered on objects - a term for a variable, which basically encompasses much more than just a piece of data. Objects, in the case of Rails, are designed to give the application:
Once you understand this, the entire spectrum of Rails functionality becomes apparent. The trick is to realize that everything you do in Rails should be tied to an object. This goes for the controllers too:
--
Ever wondered why you call resources directive in your routes, for a controller? It's because you're creating a set of resourceful routes based for it:
Do you see how it's all object orientated?
This gives you the ability to define the routes for specific controllers etc. The most important thing to note is how this will give you the ability to determine which routes / controller actions your requests should go
--
There's nothing wrong in using the controller setup as you have - the most important thing is to ensure you're able to define the custom URL argument, as to accommodate the non-object based structure
In your index action you have
def index
#push =Push.new
end
and your form has
<%= simple_form_for #push do |f| %>
so your form is looking for /pushes with post verb or pushes_path and you don't have that route in your routes.rb file so to fix this you need to add this in routes.rb:
resources :pushes
Update:
when you add resources :push rails basically creates seven different routes for you. One of which is
POST /pushes pushes#create create a new push
and if you look at the html generated by your form it would be something like:
<form action="/pushes" class="new_push" id="new_push" method="post">
// your fields
</form>
notice the action and verb so when you submit your form your routes are checked for them and since you didn't define them in your routes you were getting this error
And how will i be able to use the params i m getting from this form with this new resource addition?
Your form will take you to pushes_controller create action so first of all you'll have to define them. You can access them simply by params[:pushes] in your controller action but since you want to create a new record so you'll have to permit those attributes, checkout strong parameters
If you are using rails >= 4 then you can do
class PushesController < ApplicationController
def create
#push =Push.new(push_params)
if #push.save
redirect_to #push
else
render 'interaction/index'
end
end
private
def push_params
params.require(:push).permit(:attributes)
end
end
If you are using rails < 4 then instead of permitting these attributes(because strong parameters feature came from rails 4) you'll have to tell rails that these attributes are accessible by writing this in your pushes.rb
attr_accessible :attribute_name
Why it is assuming that its pushes controller?Because of the Push.new creation?
That's because if you look at your index action #push = Push.new so #push contains a push object with nil values(as you have just initialized it) so this is where rails magic comes, rails automatically tries to figure out url of your form and since your #push is only an initialized variable so rails takes you to create action for it. For details you should checkout rails polymorphic urls If you want your form to go to interaction_controller or some other url then you'll have to specify the url option for it
<%= form_for #push, url: "your_url_for_custom_method" %>
// other fields
<% end %>
And in the end you should really read docs
I have an action vote_for in my question controller.
what is the helper that enbales me to call this action from a view?
i tried :
vote_for_question_path(#question)
but this didn't work. ?
Since you've already defined resourceful routes for the Question resource, you should start by adding a member route on your existing resource route:
# config/routes.rb
resources :questions do
member do
get 'vote_for'
end
end
This will create the following route:
vote_for_question GET /questions/:id/vote_for(.:format) questions#vote_for
Next, create a controller action for the resulting route:
# app/controllers/questions_controller.rb
def vote_for
# logic goes here
end
Finally, in your view, you can construct a link to the route by passing the collection path to the link_to helper:
<%= link_to "Vote", vote_for_question_path(#question) %>
UPDATE:
If you'd rather represent the link as an HTML button than an <a> tag (as the OP is proposing in the comments to this answer), you can use the button_to form helper as follows:
<%= button_to "Vote", vote_for_question_path(#question), method: "get" %>
Note that, because you're replacing the link with a button, you should ensure that you're passing the correct HTTP submission method (which is GET in this instance) as an argument.
The path helpers only come when you define them in your routes.rb as a named route. So if you want a named non-RESTful route (which you do), you should add to your routes file:
get 'vote_for_question/:id', to: 'question#vote_for', as: 'vote_for_question'
And then you can call vote_for_question_path(#question.id) in your views and it will generate e.g. /vote_for_question/1.
See http://guides.rubyonrails.org/routing.html#generating-paths-and-urls-from-code for more on this.
all, I'm trying to get a custom action to work with a put method: in the
in _post.html.erb i have a link_to statement:
<%= link_to 'End now', post, :method => :put, :action => endnow %>
routes.rb contains:
resources :posts do
member do
put :endnow
end
and posts_controller.rb looks like:
class PostsController < ApplicationController
helper_method :endnow
[.. code for create, edit, destroy, etc ..]
def endnow
puts params
end
end
rake routes's relevant line looks like:
endnow_post PUT /posts/:id/endnow(.:format) posts#endnow
However, the action endnow helper doesn't run when clicking on this link.
Strangely, it does run with an index action (which i can tell from the puts command.
Of course, eventually the code for endnow will update #post, but for now, it just doesn't run properly.
Maybe i'm going about this the wrong way - all I'm trying to achieve is to update #post upon clicking the link to that post, and before showing it.
Any ideas / Alternatives?
Why not use the route helper method provided to you? Change your link to
<%= link_to 'End now', endnow_post_path(#post), method: :put %>
Things you're doing wrong:
If you want to specify the :action, use the Symbol for the action (you're missing a colon). :action => endnow should be action: :endnow
I will assume you have a #post instance variable you're passing from your controller to your action. You should be using that instead of post (unless you do in fact have a local post variable you're omitting from your code)
You are using endnow as an action; you should remove the helper_method :endnow line in your controller because it's not something you want to/should be accessing from your view.
This can all be avoided by using the route helper (for endnow_post you'd append _path to get the local route path: endnow_post_path), and pass in your #post as an argument.
Because you're trying to do a PUT request, you must make sure you have something like jquery-ujs included in your asset pipeline to convert these links to form submissions behind the scenes; browsers don't support PUT via the click of a link on their own.
As for why you're getting the template error when you get your link_to working, Rails is telling you that you need to create a app/views/posts/endnow.html.erb file. Your action has only puts params which does not terminate execution, leaving Rails to assume you still are trying to render some endnow.html.erb template.
Are there other ways to do what you're trying to do (change a single attribute of a specific model)? Sure. Are there better ways? That's pretty subjective; it may not be the most RESTful way, but it's arguably easier to deal with (if for example there are very specific authorization rules to check before updating the attribute you are modifying in endnow. Does the way you've started fleshing out work? Absolutely.
Finally, as a bump in the right direction, after you fix your link_to and remove the the helper_method as I have described above, your endnow action might look like this:
def endnow
post = Post.find!(params[:id])
post.some_attribute_here = some_new_value_here
post.save
redirect_to :root and return # <- this line sets a redirect back to your homepage and terminates execution, telling rails to do the redirect and **not** to render some endnow.html.erb file
end