I'm using nested routes and I want to provide some sort of a shortcut method. (I'm using RoR 3.0)
The routes look like this.
resources :countries do
resources :regions do
resources :wineries
end
end
To access a winery route I want to be able to define a function that removes the need to specify a country and region each time. Like:
def winery_path(winery)
country_region_winery_path (winery.country, winery.region, winery)
end
Where should I do this? How can I get that to be available whereever url_for is available?
I would put it into your app/controller/application_controller.rb
class ApplicationController < ActionController::Base
helper_method :winery_path
def winery_path(winery)
country_region_winery_path (winery.country, winery.region, winery)
end
end
Now it's available in every controller and view
Related
I have an email_template model that has a nested resource moves to handle moving an email_template from one folder to another.
However, I want to namespace these actions in a :templates namespace because I have several other resources that are template items as well.
Since I'm namespacing, I don't want to see templates/email_templates/:id in the URL, I'd prefer to see templates/emails/:id.
In order to accomplish that I have the following:
# routes.rb
namespace :templates do
resources :emails do
scope module: :emails do
resources :moves, only: [:new, :create]
end
end
end
Everything works fine when I do CRUD actions on the emails, since they are just using the :id parameter. However, when I use the nested moves, the parent ID for the emails keeps coming across as :email_id and not :email_template_id. I'm sure this is the expected behavior from Rails, but I'm trying to figure out how the parent ID is determined. Does it come from the singular of the resource name in the routes, or is it being built from the model somehow?
I guess it's ok to use templates/emails/:email_id/moves/new, but in a perfect world I'd prefer templates/emails/:email_template_id/moves/new just so developers are clear that it's an email_template resource, not a email.
# app/controllers/templates/emails_controller.rb
module Templates
class EmailsController < ApplicationController
def show
#email_template = EmailTemplate.find(params[:id])
end
end
end
# app/controllers/templates/emails/moves_controller.rb
module Templates
module Emails
class MovesController < ApplicationController
def new
# Would prefer to reference via :email_template_id parameter
#email_template = EmailTemplate.find(params[:email_id])
end
def create
#email_template = EmailTemplate.find(params[:email_id])
# Not using strong_params here to demo code
if #email_template.update_attribute(:email_tempate_folder_id, params[:email_template][:email_template_folder_id])
redirect_to some_path
else
# errors...
end
end
end
end
end
You could customize the parameter as:
resources :emails, param: :email_template_id do
...
end
I have a Users table which also has a manager's id to implement a self-join. when I login as a a manager and click on "My subordinates", I should see my subordinates. The subordinates are also from the User table.
So my question is
What should I say here <%= link_to "My Subordinates", ????_path %>(I mean like user_path.).
How should the model and controller logic be?
I would do something like #ryanfelton said, but instead of overwriting the index method, i would create a new one specifically for the subordinates.
class Manager::UsersController < ApplicationController
before_action :ensure_manager! #this one check the manager_id or any other condition to be manager
def sobordinates
#subordinates = #user.subordinates
end
end
#routes.rb
namespace :manager do
resources :users do
collection do
get :subordinates
end
end
end
This way you can maintain the index of users and you have a method only for the subordinates.
Be aware that you need to create a subordinates.html.erb inside the users folder >
app/views/manager/users/subordinates.html.erb
EDIT:
You where asking for the model and the link also so, here it goes:
The link: after editing the routes.rb, go to the console and use rake routes
and search for the subordinates link. Add the _path or _url depending on the use you are whiling for that path.
The model, I strongly recommend you to read the official documentation about relations: http://guides.rubyonrails.org/association_basics.html. That would help you more than having the answer for copying and pasting :)
I would recommend namspacing a users_controller.rb.
So it would be in the folder app/controllers/manager/users_controller.rb
class UsersController < ApplicationController
before_action :ensure_manager!
def index
#manager.users
end
end
In the routes.rb you would have this route:
namespace :manager do
resources :users
end
So ultimately your path would be manager_users_path
I want to add a method called quick_view, which is basically a show method but much simpler and meant to be served with Ajax on hover on a product.
How can i achieve this ? How can i open the ProductsController of spree and add before_filters and also specify the appropriate routes..
Thanks !
Doco for that is at https://guides.spreecommerce.com/developer/logic.html
Create a class called app/controllers/products_controller_decorator.rb, and put something like this in it:
Spree::ProductsController.class_eval do
before_filter :my_filter, :only => :quick_view
def quick_view
# your code goes here
end
private
def my_filter
# code for your before filter goes here
end
end
As for the routes, you'll be able to add it in your routes.rb file just like any other route, but you'll need to specify that it's a spree route:
Spree::Core::Engine.routes.draw do
# Your route goes inside this block
end
I want to create a method that, when called from a controller, will add a nested resource route with a given name that routes to a specific controller. For instance, this...
class Api::V1::FooController < ApplicationController
has_users_route
end
...should be equivalent to...
namespace :api do
namespace :v1 do
resources :foo do
resources :users, controller: 'api_security'
end
end
end
...which would allow them to browse to /api/v1/foo/:foo_id/users and would send requests to the ApiSecurityController. Or would it go to Api::V1::ApiSecurityController? It frankly doesn't matter since they're all in the same namespace. I want to do it this way because I want to avoid having dozens of lines of this:
resources :foo do
resources :users, controller: 'api_security'
end
resources :bar do
resources :users, controller: 'api_security'
end
Using a method is easier to setup and maintain.
I'm fine as far as knowing what to do once the request gets to the controller, but it's the automatic creation of routes that I'm a little unsure of. What's the best way of handling this? The closest I've been able to find is a lot of discussion about engines but that doesn't feel appropriate because this isn't separate functionality that I want to add to my app, it's just dynamic routes that add on to existing resources.
Advice is appreciated!
I ended up building on the blog post suggested by #juanpastas, http://codeconnoisseur.org/ramblings/creating-dynamic-routes-at-runtime-in-rails-4, and tailoring it to my needs. Calling a method from the controllers ended up being a bad way to handle it. I wrote about the whole thing in my blog at http://blog.subvertallmedia.com/2014/10/08/dynamically-adding-nested-resource-routes-in-rails/ but the TL;DR:
# First draft, "just-make-it-work" code
# app/controllers/concerns/user_authorization.rb
module UserAuthorization
extend ActiveSupport::Concern
module ClassMethods
def register_new_resource(controller_name)
AppName::Application.routes.draw do
puts "Adding #{controller_name}"
namespace :api do
namespace :v1 do
resources controller_name.to_sym do
resources :users, controller: 'user_security', param: :given_id
end
end
end
end
end
end
end
# application_controller.rb
include UserAuthorization
# in routes.rb
['resource1', 'resource2', 'resource3'].each { |resource| ApplicationController.register_new_resource(resource) }
# app/controllers/api/v1/user_security_controller.rb
class Api::V1::UserSecurityController < ApplicationController
before_action :authenticate_user!
before_action :target_id
def index
end
def show
end
private
attr_reader :root_resource
def target_id
# to get around `params[:mystery_resource_id_name]`
#target_id ||= get_target_id
end
def get_target_id
#root_resource = request.fullpath.split('/')[3].singularize
params["#{root_resource}_id".to_sym]
end
def target_model
#target_model ||= root_resource.capitalize.constantize
end
def given_id
params[:given_id]
end
end
I have nested resources like so
resources :users do
resources :widgets
end
When I have #widget, to get a proper routing from my helpers i need to use user_widget_path(#widget.user, #widget) is there any way to tell rails to automatically pull out the user from #widget object? So i could just use user_widget_path(#widget)
#apneadiving is totally right. But you can improve a little your approach:
link_to "user", user_widget_path(#widget.user, #widget)
can be presented shorter:
link_to "user", [#widget.user, #widget]
UPD
Also you can rewrite user_widget_path as you want:
class ApplicationController < ActionController::Base
helper_method :user_widget_path
private
def user_widget_path(widget)
super(widget.user, widget)
end
end
You should also rewrite edit_user_widget_path, new_user_widget_path. And better to wrap it as an external Module.
There is no automatic method to do this. But you could create your own application helper, it's pretty straight.