Routing a resource to controller - ruby-on-rails

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

Related

creating a form to route a method inside controller

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'.

Update attributes rails - No route matches [POST]

I'm trying to basically update my integration object attribute "filters". I have a integrations controller and what seems the proper actions to do so. But when I try to save after filling out the text-field I get this error No route matches [POST], I understand what it's saying but isn't update a post? Here is my code for clarity.
Controller
def update
#integrations = current_account.integrations.find(params[:id])
attrs = params.require(:integration).permit(:filters)
if #integrations.update_attributes(attrs)
redirect_to account_integration_path
else
render :filters
end
end
def filters
#integrations = current_account.integrations.find(params[:id])
end
View
<%= form_for #integrations, url: filters_account_integration_path do |f| %>
<%= f.text_field :filters, class: "tag-autocomplete" %>
<%= link_to "Save", account_integration_path, method: :post, class: [ "button", "button--modal" ] %>
<% end %>
Routes
resources :integrations, only: [ :index, :destroy, :update ] do
get "filters", on: :member
end
Hopefully that is enough info let me know if you need more? My basic question is why is this not updating the integration object? Isn't update a post?
resources generates seven routes by default. You're using it to generate only three of those. Those three routes will look like this:
GET /integrations
DELETE /integrations/:id
PATCH /integrations/:id/edit
Your form, on the other hand, is trying to use this route:
POST /integrations/:id
which doesn't match any of the generated routes.
Instead, try using the default form helpers:
<%= form_for #integrations, url: url_for(:controller => :integrations, :action => :update, :id => #integrations.id) do |f| %>
<%= f.text_field :filters, class: "tag-autocomplete" %>
<%= f.submit "Save" %>
<% end %>
That's assuming that #integrations is a single Integration resource. If it isn't, you have bigger problems than just this.

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

Rails 4 - Toggle Boolean to false on click

I am trying to use Rails 4 to build an app.
The app has 3 models - one for Project, one for Scope and one for Finalise.
Finalise belongs to scope. Scope belongs to Project. Project accepts nested attributes for Scope (and Finalise) and Scope accepts nested attributes for Finalise.
In my finalise model, I have a boolean attribute for :draft. If draft is true, then I want to include a link on the project show page to toggle the :draft to false when the draft is complete.
A SO member has given me some suggestions in the attached (which I have tried to follow, but have not served to toggle the boolean attribute).
In my projects controller, I have:
def new
#authorise #project
#project = Project.new
#project.scope = Scope.new
#project.scope.finalise = Finalise.new
end
In my scopes controller, I have;
def new
#scope = Scope.new
#scope.finalises.build
end
In my finalises controller, I have a method (which was suggested by another SO user):
def toggle_draft
#finalise = Finalise.find(params[:id])
#finalise.draft = true
#finalise.save
redirect_to project_path(#project)
end
The finalise route has:
resources :finalises do
patch '/toggle-draft', to: 'finalises#toggle_draft', as: 'toggle_draft'
end
The finalise partial show (which is incorporated in the project show) has:
<% if #project.scope.finalise.draft == true %>
<div class="finalise"> <%= link_to 'Finalise this draft',
finalise_toggle_draft_path(:id => #finalise.id), :remote => true, method: :patch %></div>
<% end %>
When I try this I get an error that says:
undefined method `id' for nil:NilClass
Gabriel (below) has suggested that I might need to link through the associations (so #project.scope.finalise.id). I have tried that formulation and #project.scope.finalise_id. Neither of these work either.
When I try it as:
<% if #project.scope.finalise.draft == true %>
<div class="finalise"> <%= link_to 'Finalise this draft',
finalise_toggle_draft_path(:id => #project.scope.finalise.id), :remote => true, method: :patch %></div>
<% end %>
I get an error that says:
No route matches {:action=>"toggle_draft", :controller=>"finalises", :id=>1} missing required keys: [:finalise_id]
When I try:
I get an error that says:
<% if #project.scope.finalise.draft == true %>
<div class="finalise"> <%= link_to 'Finalise this draft',
finalise_toggle_draft_path(:id => #project.scope.finalise.id), :action => 'toggle-draft', :remote => true, method: :patch %></div>
<% end %>
No route matches {:action=>"toggle_draft", :controller=>"finalises", :id=>1} missing required keys: [:finalise_id]
When I try:
I get this error:
<% if #project.scope.finalise.draft == true %>
<div class="finalise"> <%= link_to 'Finalise this draft',
controller: "finalises", action: "toggle_draft",
finalise_id: #finalise_id,
:remote => true,
method: :patch %>
</div>
<% end %>
No route matches {:action=>"toggle_draft", :controller=>"finalises", :id=>"53", :finalise_id=>nil, :method=>:patch}
Thank you
in projects_controller
def show
#project = Project.find(params[:id])
end
in the projects show view
<%= link_to 'Finalise draft', finalise_toggle_draft_path(#project.scope.finalise.id), method: :patch
You should be able to use the named route and pass the finalise id which you can get from #project. You'll have to be careful how you get the finalise model in the finalises#toggle_draft method, check how your params are named, probably finalise_id, and not id. It would be good to read up on nesting resources and how to pass variables between controllers.
This is what ended up working (using Margo's guidance):
finalises partial:
<div class="finalise">
<%= link_to 'Finalise draft', finalise_toggle_draft_path(projectid: #project.id, id: #project.scope.finalise.id, finalise_id: #project.scope.finalise.id), method: :patch %>
</div>
Finalises_controller
def toggle_draft
#finalise = Finalise.find(params[:id])
#finalise.draft = false
#finalise.finalised = Time.now
#finalise.save
redirect_to project_path(Project.find(params[:projectid]))
#finalise_idis not defined... You can gat the id through the relation #project.scope.finalise.id
<% if #project.scope.finalise.draft == true %>
<div class="finalise"> <%= link_to 'Finalise this draft', finalise_toggle_draft_path(id: #project.scope.finalise.id), method: :patch %></div>
<% end %>

rails admin edit view path routes

I've got an admin section setup, but am having trouble getting the "update" route to work.
Getting error when hitting "update" via the edit view:
"No action responded to 2."
For some reason the route is responding to the :id as the :action.
Parameters:
Parameters: {"commit"=>"Update", "action"=>"2", "_method"=>"put", "admin"=>{"ended_at(1i)"=>"2010", "ended_at(2i)"=>"8", "ended_at(3i)"=>"22"}, "id"=>"edit", "controller"=>"admin/subscriptions"}
The edit view uri:
/admin/subscriptions/2/edit
Edit view:
<% form_for :admin, #subscription, :html => {:method => :put} do |f| %>
<p>
<%= f.label :ended_at %><br />
<%= f.date_select :ended_at %>
</p>
<p>
<%= f.submit 'Update' %>
</p>
<% end %>
Route:
map.namespace :admin do |admin|
admin.resources :subscriptions
end
I assume I need to do something differently in the form_for method or maybe the routes, but everything I've tried isn't working.
Thanks for the help!!
It should be this:
<% form_for [:admin, #subscription] do |f| %>
By putting :admin and #subscription in square-brackets, this makes it into an array which is passed as the first argument to form_for. The benefit of this is if #subscription is a pre-existing record (as-in, one found by find, not created with new) then Rails will know to set the form method to PUT.
This works:
<% form_for :admin, #subscription, :html => {:method => :put}, :url => { :action => "update" } do |f| %>
Seems verbose though. Any better ideas?
Try
- form_for :subscription, #subscription do |f|
We're using formtastic here.

Resources