How do I have route helpers use existing params? - ruby-on-rails

Sometimes I won't have to provide a param to a route helper and it automagically pulls it in from the existing params. I can't seem to figure out how to get it to consistently work.
routes.rb:
scope ':admin_id', module: :admin do
resources :roles
end
When rendering a page where the :admin_id is set to 10:
<%= roles_path %> # /10/roles
<%= edit_role_path(my_role, admin_id: 10) %> # /10/roles/15/edit
<%= edit_role_path(my_role) %> # sometimes works
rails
routes:
roles GET /:admin_id/roles(.:format) roles#index
POST /:admin_id/roles(.:format) roles#create
new_role GET /:admin_id/roles/new(.:format) roles#new
edit_role GET /:admin_id/roles/:id/edit(.:format) roles#edit
role GET /:admin_id/roles/:id(.:format) roles#show
PATCH /:admin_id/roles/:id(.:format) roles#update
PUT /:admin_id/roles/:id(.:format) roles#update
DELETE /:admin_id/roles/:id(.:format) roles#destroy

Figured it out!
def default_url_options(options={})
{ admin_id: params[:admin_id] }
end
This will add the param to all of my route helper methods so I don't have to specify it each time.

Related

form_for routing error with scope :module nested routes

This may not make sense but I'm trying to learn harder stuff and progress, it seems like I'm missing the ID for address but can't seem to find a solution.
I included the url in form_for because when I remove it, the app breaks. But seems like I predefined the url than edit breaks.
<%= form_for([#address.user, #address], :url => user_addresses_path) do |f| %>
Error Readout:
No route matches [PATCH] "/users/1/addresses"
When I remove :url=>
undefined method `user_client_address_path'
routes.rb
Rails.application.routes.draw do
# Security Devise Setup
devise_for :admins
devise_for :users
# Main Pages
root 'website/page#index'
# Client Sections
resources :users do
scope module: "client" do
root :to => 'dashboard#index'
resources :addresses
end
end
namespace :admin do
root :to => 'panel#index'
end
end
rake routes partial output (let me know if more is needed)
user_addresses GET /users/:user_id/addresses(.:format) client/addresses#index
POST /users/:user_id/addresses(.:format) client/addresses#create
new_user_address GET /users/:user_id/addresses/new(.:format) client/addresses#new
edit_user_address GET /users/:user_id/addresses/:id/edit(.:format) client/addresses#edit
user_address GET /users/:user_id/addresses/:id(.:format) client/addresses#show
PATCH /users/:user_id/addresses/:id(.:format) client/addresses#update
PUT /users/:user_id/addresses/:id(.:format) client/addresses#update
DELETE /users/:user_id/addresses/:id(.:format) client/addresses#destroy
If you are using AJAX to submit the form, try adding method: 'POST' to it.
If you are submitting the form normally, try adding method: :post to the form_for hash.
It should end up something like:
<%= form_for([#address.user, #address], url: user_addresses_path, method: :post) do |f| %>

Rails 4 Create form to update only one attribute

I have a user model, but I need to create a form to update only one attribute.
EDIT: I added the create_mailbox patch in :users resource but the form throws a undefined methodsettings_create_mailbox_path'` error. Can anyone give me some insight to how this member patch/resource routes work?
Here's the form:
<%= form_for #user, url: settings_create_mailbox_path(#user) do |f| %>
<%= f.text_field :rss_mailbox, autocomplete: 'off'%>
<button type="submit" class="button">Create Mailbox</button>
<% end %>
Here's the Users route:
resources :users, id: /.*/ do
member do
patch :settings_update, controller: :settings
patch :create_mailbox, controller: :settings
patch :view_settings_update, controller: :settings
patch :sharing_services_update, controller: :sharing_services
patch :actions_update, controller: :actions
end
end
And here's the settings route:
get :settings, to: 'settings#settings'
namespace :settings do
get :account
get :billing
get :import_export
get :feeds
get :help
post :update_credit_card
post :mark_favicon_complete
post :update_plan
post :font
post :font_increase
post :font_decrease
post :entry_width
end
It would depend on the attribute and what you're changing it to.
If it's a simple toggling of a boolean field, for example, you could get away with a link that fires off an ajax request, that makes the change and returns some HTML (eg. to update the link you clicked).
If it's something else, eg. a text field or a string or something, a form_for #user would be the typical way. But the form would only have one field, and the controller that processes the form post would have its strong parameters (or attr_accessible for Rails 3) set so that it will only accept data for that one field.
Was using the wrong route name. This was the right one:
create_mailbox_user_path
Rails 4 Use Strong Parameters to determine which attribute is allow to update like so:
def user_param
params.require(:user).permit(:attr)
end

NoMethodError when rendering a form Rails

routes.rb:
resources :shops
shop_controller.rb:
def new
#shop=Shop.new
end
new.html.erb:
<%= form_for(#shop) do |f| %>
....
<% end %>
error:
undefined method `shops_path' for:
<%= form_for(#shop) do |f| %>
The problem is that I already specify the shop resources in the routes file.
Why still get such kind of error?
Any help will be appreciated, thanks
You should use ShopsController not ShopController due to Rails naming convention.
Make sure you have these lines in your rake routes output:
shops GET /shops(.:format {:action=>"index", :controller=>"shops"}
POST /shops(.:format) {:action=>"create", :controller=>"shops"}
OR
shops POST /shops(.:format) {:action=>"create", :controller=>"shops"}
If they aren't present, look carefully at your routes.rb for possible with_options, scope or any other scoping that can affect your resources :shops in such a way that it doesn't generate default url helpers.
since u havent specified the method in the form tag, i guess it is going as a GET request. Try adding the method to ur form
<%= form_for(#shop), :method => :post do |f| %>

Rails - custom action in controller - how to reference in view?

I'm using a custom action to get the id of a project into the session, so that only relevant info for that project is shown in other areas. I've made a custom action in the projects controller, and am having trouble getting a link to work in the view to call that action. I just get an error saying "Couldn't find project without ID". I'm new to rails - I know it's probably an easy question, but help would be much appreciated, thanks!
View Code:
<%= link_to 'Select Project', :action => :select_project %>
Controller Code:
def select_project
#project = Project.find(params[:id])
session[:project_id] = #project.id
end
Routes:
resources :projects do
collection do
get :select_project
end
end
Alternative routes code:
resources :projects do
put 'select_project', on: :member
end
This is untested but I believe it is what you are looking for:
Routes:
resources :projects do
member do
post :set_current
end
end
this should create the following:
Endpoint: /projects/:id/set_current POST
Helper: set_current_project_path
Controller
def set_current
project = Project.find(params[:id])
session[:project_id] = project.id
redirect_to projects_path, :notice => "Current project set to #{project.name}"
end
Views
# index / erb tags excluded for simplicity
#projects.each do |project|
link_to 'Select Project', set_current_project_path(project), :method => :post
end
# show
<%= link_to 'Select Project', set_current_project_path(#project), :method => :post %>
See:
http://guides.rubyonrails.org/routing.html#adding-more-restful-actions
http://guides.rubyonrails.org/routing.html#crud-verbs-and-actions
Note also the use of 'post' instead of 'get', since we are changing the state of an object (session)
it is preferred to use a post not a get, otherwise users might pull up an old get request in the address bar
of their browser and set their session to a project unknowingly.
like varatis said - use rake routes or CONTROLLER=projects rake routes to help with determining what your route/path helpers look like and what http verbs they are expecting
And is there a reason why it's project not #project in the controller
The #project creates an instance variable; in a rails controller instance variables are made available to the views. This set_current action will never render a view, so no reason to make an instance variable out of it.
How come you have to set it to member and not collection in the routes
any action where you want to reference params[:id] should be a member route, an alternative would be to leave it as a collection route and pass params[:project_id] and pass that in all of your link_to calls, but in this case member makes more sense.
I believe resources :projects is a short cut for this break down
member do
get :show
get :edit
put :update
delete :destroy
end
collection do
get :index
get :new
post :create
end
hopefully that clarifies your questions some?
I think the route generated would be select_project_projects_path.
Link:
<%= link_to 'Select Project', select_project_projects_path %>
For future reference, run rake routes to see the automatic route helpers generated by Rails.

How do I render a partial for a view of a nested resource? - Rails 3.1

This is my route:
scope ":username" do
resources :feedbacks
end
I am on my home/index.html.erb view and I am trying to do this:
<%= render "feedbacks/form" %>
But this gives me this error:
ActionView::Template::Error (No route matches {:controller=>"feedbacks", :format=>nil}):
1: <%= form_for(#feedback) do |f| %>
2: <% if #feedback.errors.any? %>
3: <div id="error_explanation">
4: <h2><%= pluralize(#feedback.errors.count, "error") %> prohibited this feedback from being saved:</h2>
app/views/feedbacks/_form.html.erb:1:in `_app_views_feedbacks__form_html_erb__3181571289116259961_2487495480'
app/views/home/index.html.erb:18:in `_app_views_home_index_html_erb___397233383548615486_2487321620'
This is my rake routes for feedbacks:
feedbacks GET /:username/feedbacks(.:format) {:action=>"index", :controller=>"feedbacks"}
POST /:username/feedbacks(.:format) {:action=>"create", :controller=>"feedbacks"}
new_feedback GET /:username/feedbacks/new(.:format) {:action=>"new", :controller=>"feedbacks"}
edit_feedback GET /:username/feedbacks/:id/edit(.:format) {:action=>"edit", :controller=>"feedbacks"}
feedback GET /:username/feedbacks/:id(.:format) {:action=>"show", :controller=>"feedbacks"}
PUT /:username/feedbacks/:id(.:format) {:action=>"update", :controller=>"feedbacks"}
DELETE /:username/feedbacks/:id(.:format) {:action=>"destroy", :controller=>"feedbacks"}
Edit 1
When I pass in the local instance variable #feedback like this: <%= render "feedbacks/form", :local => #feedback %> which is pulling from my home controller, where it is declared like this:
class HomeController < ApplicationController
def index
#users = User.all
#feedback = Feedback.new
end
end
I still get this error:
Routing Error
No route matches {:controller=>"feedbacks", :format=>nil}
Edit 2
I also have a users resource specified in my routes file, that looks like this:
resources :users
scope ":username" do
resources :feedbacks
end
Seems like form_for can't find the correct route, this line suggests you don't have an instance variable #feedback set when trying to render that partial:
(No route matches {:controller=>"feedbacks", :format=>nil})
Notice there is no :id parameter in that hash (which is likely being passed to the router to generate the correct URL to submit the form to).
Do you define a #feedback somewhere in the controller action (preferable) or views you're using? If you think you are, try the following above line 1 of your partial:
logger.info "feedback object: #{#feedback.inspect}"
Edit:
First of all, locals should be passed not as :local => #feedback but as:
:locals => {:variable_name_in_partial => value_for_variable_name}
Second of all, you are trying to access #feedback which is an instance variable accessible to views even if it's not passed explicitly (as long as it's set). So as long as you set it in the HomeController#index method you don't need to pass it to any views locally.
Also, you are not using the correct syntax for rendering partials (wish I had noticed earlier!).
Change the following:
<%= render "feedbacks/form" %>
To this:
<%= render :partial => "feedbacks/form" %>
Aren't you forgetting to pass in :username? Your route says scope :username
If I add a route like yours, open up the Rails console, include Rails.application.routes.url_helpers and run feedbacks_path, I get a routing error, but feedbacks_path :username => 'bob' works fine.
> feedbacks_path(:username => 'bob')
=> "/bob/feedbacks"
Are you sure you want scope? What about a nested resource as per:
resources :users do
resources :feedbacks
end
Also, I've had trouble when using controllers with plural names. You might try renaming FeedbacksController to FeedbackController.

Resources