How do I create a rails controller action? - ruby-on-rails

My rails app has a single CustomerSelectionController, with two actions:
index: which shows a form where the user can enter customer information and
select: which just displays a static page.
class CustomerSelectionController < ApplicationController
def index
end
def select
end
end
I've created an entry in my routes.rb file:
resources :customer_selection
and the form in the index view looks like:
<h1>Customer Selection</h1>
<%= form_tag("customer_selection/select", :method => "get") do %>
<%= submit_tag("Select") %>
<% end %>
however when I click on the Select button in the browser, all I get is:
Unknown action
The action 'show' could not be found for CustomerSelectionController
I'm not sure why it is trying to perform an action called show? I haven't defined or referenced one anywhere.

I'm not sure why it is trying to perform an action called show? I haven't defined or referenced one anywhere.
Yes you have. That's what resources does. It defines the seven default RESTful routes: index, show, new, create, edit, update and destroy. When you route to /customer_selection/select, the route that matches is "/customer_action/:id", or the "show" route. Rails instantiates your controller and attempts to invoke the "show" action on it, passing in an ID of "select".
If you want to add a route in addition to those, you need to explicitly define it, and you should also explicitly state which routes you want if you don't want all seven:
resources :customer_selection, only: %w(index) do
collection { get :select }
# or
# get :select, on: :collection
end
Since you have so few routes, you can also just define them without using resources:
get "/customer_selection" => "customer_selection#index"
get "/customer_select/select"
Note that, in the second route, the "customer_select#select" is implied. In a route with only two segments, Rails will default to "/:controller/:action" if you don't specify a controller/action.

Related

Custom action_item on show page only

I'm struggling to create an action_item for a show page (not the index) of a resource. I need to add a button on the show page, which when the user clicks it, updates a single attribute on the resource (in this case 'status' of a SupportSession). I have created a method on my SupportSession model called approval_confirmed which accepts a parameter called support_session_id - I'd like this method to be called.
(BTW I'm not sure which HTTP verb to use (patch, put, get) though I've settled on patch).
Here's how my resource is set-up:
ActiveAdmin.register SupportSession, as: "SUSupportSession" do
(I've given this resource a custom name/alias because different users use this resource in different ways; so for simplicity I keep them in separate files.)
Here is my action_item code:
action_item only: [:show] do
link_to 'Approve session', approve_su_support_session_path, method: :patch
end
Here is the corresponding member_action (which I understand is called by the action_item?):
member_action :approve, method: :patch do
SupportSession.with(support_session_id: resource.id).approval_confirmed
redirect_to su_support_session_path, notice: "Your support session has been approved!"
end
This creates a new route (output of rails routes below):
approve_su_support_session PATCH /su_support_sessions/:id/approve(.:format) su_support_sessions#approve
However, when I try to open the index page (to select a record from the table and move to its show page) I get this error:
ActionController::UrlGenerationError in SuSupportSessions#index
No route matches {:action=>"approve", :controller=>"su_support_sessions"}, missing required keys: [:id]
I understand this is something to do with the fact that there is no id parameter on the index page (although I don't understand why it's getting called on the index page because I only need this button on the show page - where the id will appear once a user clicks 'view' on any item listed in a table).
Thanks for your help. I think I'm getting terribly mixed up with how ActiveAdmin controllers connect to the underlying model.
As #max says in comment above your have to pass an argument to your path, resource or resource.id works.
Regarding your current error I guess it could be caused because you have not mentionned the action you want to do.
action_item :approve, only: [:show] do
link_to 'Approve session', approve_su_support_session_path(resource), method: :patch
end
I hope it helps. Let me know.

Rails 4 routing a value besides :id

I either have an issue with my link_to code in my view or my route. I am trying to pass in a non primary key value from a view and do a query using that value. No matter what I do rails always just takes the :id of that table as its only param.
Here is my view
<td> <%= link_to c.app_version_id, compliance_suite_path(:app_version_id => c.app_version_id) %></td>
My Route
resources :suites, :only => [:index] do
member do
get 'report'
end
member do
get 'compliance', param: :app_version_id
end
end
If I do a rake routes I get
compliance_suite GET /suites/:id/compliance(.:format) suites#compliance {:param=>:app_version_id}
Here is my controller which right now is just trying to view the prams list
def compliance
Rails.logger.info "***********PARAMS PARAMS *******************"
Rails.logger.info {params.inspect}
end
I do have other methods in that controller that use the :ID I just have this one method I want to use another value an app version id to do a query. So I don't want the entire controller to use this other id just 1 method. The value I want is in my view I can see it in my table. In my controller its always just the :id and never the app_version_id.
Its either my route or my link_to?
Because your route is a nested member route, rails expects the id of the parent. You don't really need to include the params clause in your route. It would be better to change your route to reflect your intentions by including the app_version_id in the route.
routes.rb
get 'suite/:app_version_id/compliance', to: 'suites#compliance', as: 'compliance_suite'

Rails form builder with admin namespace

The code below works well to create new transactions on the Invoice show view. It however doesn't work when in admin namespace. i.e /admin/invoices/1/ but works on /invoices/1/
show.html.erb
<%= form_for([#invoice, #invoice.transactions.build]) do |form| %>
....
transactions form input
routes.rb
resources :invoices do
resources :transactions
end
When calling form_for in a namespace route like /admin/invoices/1/, Rails will automatically append admin to your route. In other words, form_for([#invoice, #invoice.transactions.build]) would POST to a route like /admin/invoice/:id/transactions/ rather than /invoice/:id/transactions/.
To fix, explicitly set the URL of the form and use a route helper method to infer the correct route:
form_for(#invoice, url: invoice_transaction_url(#invoice.id))
Note that you may need to replace invoice_transaction_url with the correct route. Use rake routes to find the helper method that corresponds to the desired controller POST action.

Calling a specific action in a form tag

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.

Rails 4 Routing - undefined local variable

I have a payments table. In the index view I list all payments in a table and in the show view I'd like to show a form of all payments where a user can select which ones to further process.
Above the table in the index action view I have:
<%= link to "Customise", show_payment_path %>
Then in the controller:
def show
#payments = Payment.all
end
In my routes file:
resources :payments
The error I am getting is:
undefined local variable or method `show_payment_path'
I have tried
<%= link_to 'Customise Sepa Mandate', show_payments_path %>
as well but that gives the same error. As does using url instead of path.
The path for resourceful-routed show actions is just payment_path (singular resource) or payment_path(id). Your “customize” link would lead me to believe you actually want edit_payment_path(id), though.
See Rails Guides — Generating Paths and URLs From Code for more info.
Run rake routes command to see available routes and correct syntax.
Pass show_payment_path(:id) to get the particular payment show page.
for that make your own routes and create their own path variable such as
resources :payments, except: [:show] do
get '/show' => "payments#show", on: collection, as: :show
end

Resources