I have a route something like:
scope ":department", department: /admin|english|math/, defaults: { department: 'admin' }
Is it possible to make the default department for this route to be based on the current_user.department.name
?
If this is not possible, what is another way of solving my problem. The problem is that I want all links to default to the current scope unless otherwise noted. I'm currently doing the following in LOTS of places:
# links to /math/students
link_to 'students', students_path(department: current_user.department.name.downcase)
If I understand correctly, what you want is to be able to write:
link_to 'students', students_path
and have the department option automatically set based on the current user.
Here's a solution that's like some of the others that have been offered: define helpers for each route that requires a department. However, we can do this programmatically.
Here we go:
app/helpers/url_helper.rb
module UrlHelper
Rails.application.routes.routes.named_routes.values.
select{ |route| route.parts.include?(:department) }.each do |route|
define_method :"department_#{route.name}_path" do |*args|
opts = args.extract_options!
if args.size > 0
keys = route.parts - [:department]
opts.merge!(Hash[*keys.zip(args).flatten])
end
opts.reverse_merge!(department: current_user.department.name.downcase)
Rails.application.routes.url_helpers.send(:"#{route.name}_path", opts)
end
end
end
You now have helper methods like department_students_path
for every route that has a :department
path segment. These will work just like students_path
-- you can pass in opts, you can even set the :department
explicitly and it will override the default. And they stay up to date with changes to your routes.rb
without you having to maintain it.
You might even be able to name them the same as the original helpers, i.e.,
define_method :"#{route.name}_path"
without having to prefix them with department_
--I didn't do that because I'd rather avoid naming collisions like that. I'm not sure how that would work (which method would win the method lookup when calling it from a view template), but you might look into it.
You can of course repeat this block for the _url
helper methods, so you'll have those in addition to the _path
ones.
To make the helpers available on controllers as well as views, just include UrlHelper
in your ApplicationController
.
So I think this satisfies your criteria:
:department
which will default to the current_user
's department, so that you don't have to explicitly specify this every time.:department
segment, so you don't have to maintain them.department_student_path(@student)
. However, one limitation is that if you want to override the department, you need to do so in the final opts hash (department_student_path(@student, department: 'math')
). Then again, in that case you could always just do student_path('math', @student)
, so I don't think it's much of a limitation.Route contraints can accept a proc, so you could solve this problem with the following "hack":
concern :student_routes do
# all your routes where you want this functionality
end
# repeat this for all departments
scope ":department", constraints: lambda{|req| req.session[:user_id] && User.find(req.session[:user_id]).department.name.downcase == "english"}, defaults: { department: 'english' } do
concerns :student_routes
end
Route concerns is a feature of rails 4. If you don't use rails 4, can you get the feature with this gem: https://github.com/rails/routing_concerns.
You can also just copy all the routes for students to all of the scopes.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With