creating a form to route a method inside controller - ruby-on-rails

I am trying to create a form that redirects to a method called accept_item on the form controller. My issue is that it's not going through the accept_item method when I submit the form.
form_controller.rb
def accept
#form = Form.find(params['id'])
end
def accept_item
redirect_to inventories_path
end
accept.html.erb
<%= form_tag accept_item_forms_url do %>
<% #form.items.each do |i| %>
<%= label_tag 'Item Name' %>
<p><%= i.name %></p>
<%= label_tag 'Quantity' %>
<p><%= text_field_tag 'quantity', i.quantity %></p>
<% end %>
<%= submit_tag 'Accept', class: 'btn btn-default btn-about pull-left', data: {confirm: 'Are you sure you want to accept?'} %>
<% end %>
routes.rb
resources :forms do
collection do
get :accept_item, :as => :accept_item
end
end
Error Message
No route matches [POST] "/forms/accept_item"

The form_tag helper uses the HTTP POST method by default. You defined your routes with get:
get :accept_item, :as => :accept_item
You should use post instead:
post :accept_item, :as => :accept_item
Also I don't think you need the as: :accept_item part, unless you're going to use accept_item_url instead of accept_item_forms_url.

just remove :as => :accept_item, and change method to post
post :accept_item
You will get /foo when using :as => 'foo'.

Related

Rails - Silmple Form calls a specified action of my user controller

My problem is that when i try to call a specified method from a simple_form_for form it doesn't work.
Here is my code :
<%= simple_form_for #user, :url => {:action => :register_iban}, :html => { :method => :post } do |f| %>
<div class="col-md-8">
<%= f.input :first_name, :label => t('user-show.payment.form.first_name'), placeholder: "Prénom" %>
<%= f.input :last_name, :label => t('user-show.payment.form.last_name'), placeholder: "Nom" %>
<%= f.input :iban, :label => t('user-show.payment.form.iban'), placeholder: "IBAN" %>
<%= f.input :bic, :label => t('user-show.payment.form.bic'), placeholder: "BIC" %>
</div>
<div class="col-md-8 text-center">
<%= f.submit t('user-show.payment.title'), class: 'btn btn-danger' %>
</div>
<% end %>
So, as you can see, i try to call register_iban method from my user controller.
But when i do that, i have an error : No route matches {:action=>"register_iban", :controller=>"users", :id=>"5", :locale=>nil}
Everytime i create a new method in a controller, i have to create a route in the routes.rb file ? Here, i'd like to make this url : /users/5/register_iban (where "5" is the user id) call my method.
Sorry but i start in ruby and i'm pretty stuck :/
in your config/routes.rb try to add in the users resources
resources users do
member do
post :register_iban
end
end
No route matches {:action=>"register_iban", :controller=>"users", :id=>"5", :locale=>nil}
This error means you're trying to access a route which doesn't exist.
The routes are defined at config/routes.rb:
#config/routes.rb
resources :users do
post :register_iban
end
This will allow you to call the register_iban method in the users controller through your form.
You'll also want to make sure you're calling routes with the appropriate helpers:
<%= simple_form_for #user, url: user_register_iban(#user) %>

How to make a link_to that redirects and submits a form

I have a modal that will serve as a disclaimer in my app and I need the link at the bottom of the modal that says "agree & continue" to toggle a boolean and input the time that the boolean was toggled. I have created the button as a form with hidden links but I cant seem to see how to make it submit the form AND redirect to the path i specify. Here is my link_to code now.
<% if current_user.user_record.blank? %>
<%= form_for :user do |f| %>
<% f.hidden_field :disclosure_acceptance, :value => true %>
<% f.hidden_field :disclosure_date, :value => Time.now %>
<%= link_to("Agree & Continue", user_steps_path(current_user), class: "btn btn-primary") %>
<% end %>
<% end %>
First, create a new method in your user_records_controller or at whichever controller action the form is displayed at:
def new
#user_record = current_user.build_user_record
end
Put this in your view:
<% if current_user.user_record.blank? %>
<%= form_for #user_record do |f| %>
<%= f.hidden_field :disclosure_acceptance, :value => true %>
<%= f.hidden_field :disclosure_date, :value => Time.now %>
<%=f.submit "Agree & Continue", class: "btn btn-primary") %>
<% end %>
<% end %>
Make a create action for the user_record that looks like this:
def create
#user_record = current_user.build_user_record(permitted_params)
if #user_record.save
redirect_to user_steps_path(current_user)
else
render :new
end
end
private
def permitted_params
params.require(:user_record).permit(:disclosure_acceptance , :disclosure_date) #etc
end
UPDATE
If you directly want to jump to the 'create' action, you can make your configuration like this:
Add a custom action to your routes:
post 'rate/:article_id' => 'user_records#create' :as => :create_user_record
#or whichever controller/action you wish
You should update the route on your form:
= form_tag create_user_record_path, :method=>'post' do
#etc
In order to create a user_record from the controller, you need to change things a little bit:
def create
current_user.user_record.create(:user_id => current_user.id, :disclosure_acceptance => params[:disclosure_acceptance] , :disclosure_date => params[:disclosure_date])
if current_user.user_record.save
#etc
end

Sending URL params via a form_tag and select_tag

I'm using nested resources, and in order to make a new Round, you need to have the id of its Case, so my routes.rb includes the following:
resources :cases do
resources :rounds
end
So, when a user hits the 'new round' button on the homepage, it first directs them to a page where they can pick a case that the round belongs to, before redirecting to the round form.
For the pick_case view, I have the following:
<%= form_tag new_case_round_path, method: :get do |f| %>
<%= f.select_tag :case_id,
options_for_select(Case.all.collect { |c| [c.title, c.id] }),
class: "chosen-select" %><br/>
<%= f.submit_tag "Create round", class: "btn btn-primary" %>
<% end %>
However, rails forces me to name a case_id in the new_case_round_path, so it gives me this error before it loads the pick_case view:
No route matches {:action=>"new", :controller=>"rounds"} missing required keys: [:case_id]
How can I reference the route that the form needs to submit to when the required information for the route is being entered in the form?
No route matches {:action=>"new", :controller=>"rounds"} missing
required keys: [:case_id]
The error clearly says that case_id is missing. Rails expects case_id to be present which can't be provided in your situation as you are creating a new case instance.
One way to resolve your situation is to use Shallow Nesting which provides the route for new case
resources :cases do
resources :rounds, shallow :true
end
Now, when you run rake routes, you will find a route for new case as below
new_case GET /cases/new(.:format) cases#new
So that in your pick_case view, you can change the form to
<%= form_tag new_case_path, method: :get do |f| %>
<%= f.select_tag :case_id,
options_for_select(Case.all.collect { |c| [c.title, c.id] }),
class: "chosen-select" %><br/>
<%= f.submit_tag "Create round", class: "btn btn-primary" %>
<% end %>
Which creates a case instance first before redirecting to the round form
A bit of a work-around for the answer, I feel like there's probably a more elegant way. I added post 'get_case' => rounds#get_case to routes.rb
I added this to my rounds controller:
def get_case
id = params[:case_id]
if id
redirect_to new_case_round_path(case_id: id)
else
flash[:danger] = "An error occured. Please try again"
redirect_to pick_case_path
end
end
And this is my new pick_case view:
<%= form_tag get_case_path do %>
<%= select_tag :case_id,
options_for_select(map_with_id(Case, :title)),
class: "chosen-select" %><br/>
<%= submit_tag "Create round", class: "btn btn-primary" %>
<% end %>

Do not post a form in a Rails root route

I have a controller with just one method:
index_controller.rb
def index
# some code
end
The form:
index.html.erb
<%= form_tag :class => "form-inline signup" do %>
<div class="form-group">
<%= text_field_tag :url, nil, :class => "form-control", :placeholder => "URL do tópico" %>
</div>
<%= submit_tag "Enviar", method: :post, :class => 'btn btn-theme' %>
<% end %>
And a simple root route:
root 'index#index'
post '/', to: 'index#index'
The problem is that when I load the root page, the form is posted automatically, when the preferable was to POST just on the button call.
What am I missing here?
You should move the code for the post out to another action that can handle that.
post '/', :to => "index#submit"
Then you can define a submit action within your IndexController to handle the form, and the index action won't run the form code anymore.

Routing a resource to controller

How do you route a resource to its controller? I am using the resource in an edit page for a different model, so my actions are being routed to its model controller first.
This edit page requests from
class Grandstreamers::ResellersController < ApplicationController
def new
end etc...
I am trying to route the requests to here instead:
Grandstreamers::CertificatesController < ApplicationController
def new
end
def update
end etc...
This is my form under views/grandstreamers/resellers/edit.html.erb
<%= form_for #untrained, :url => certificates_update_path(#untrained) do |f| %>
<p> Trained Users </p>
<%= select_tag "certificate[user_id]", options_for_select(#current_trained.collect{|x| [x.name, x.id]}), {:multiple => :multiple} %>
<%= f.submit "Un-Train", class: "btn btn-large btn-primary" %>
<% end %>
<%= form_for #trained, :url => certificates_create_path(#trained) do |f| %>
<p> Non-Trained Users </p>
<%= select_tag "certificate[user_id]", options_for_select(#non_trained.collect{|x| [x.name, x.id]}), {:multiple => :multiple} %>
<%= f.submit "Train", class: "btn btn-large btn-primary" %>
<% end %>
My route is:
resources :certificates
Note that the
:url => certificates_create_path
is not correct and not working. Is there a way to specify this route in my routes.rb file or in my form? Thank you
EDIT
This is my resellers_controller edit() which is routes to first.
#trained = Certificate.new(params[:certificate])
#Trying to get to certificates_controller update. Then update the :attend to "No"
##untrained = Certificate.new(params[:certificate])
##untrained = Certificate.find(params[:id])
##untrained = Certificate.find_by_user_id(params[:id])
#untrained is not defined, I am not sure how to get it to just go to my certificate controller. For #trained I can define it since its not made yet and does not give me errors when it cant find a correct value.
My certificates controller which uses create() but cannot get to update()
def create
#trained = Certificate.new(params[:certificate])
if #trained.save
#trained.update_attributes(attend: "Yes")
end
redirect_to grandstreamers_resellers_path
end
def update
#untrained = Certificate.find(params[:id])
#untrained.update_attributes(attend: "No")
redirect_to grandstreamers_resellers_path
end
Major Issue
The instance variable #trained and #untrained need to be defined somehow in reseller_controller. What can I define them as to load the edit page?
Part Solution
I defined this is in my resellers_controller and it loads the edit page now.
#untrained = User.find(params[:id])
Now I get this error:
No route matches [PUT] "/certificates.1"
I believe the problem is you need to let routing know the full name to the controller.
From the Rails routing guide:
scope module: 'Grandstreamers' do
resources :certificates
end
Use these paths when creating the form:
<%= form_for #untrained, :url => certificate_path(#untrained), :method => :put do |f| %>
<%= form_for #trained, :url => certificates_path, :method => :post do |f| %>
use this his routes.rb file
namespace :grandstreamers do
resources :certificates
end

Resources