Reputation: 8076
I would like to declare some values in my controller that will be used by a method in its parent class. What is the best way to do this? My parent controller has an index
method that provides pagination, for example:
class BaseController < ApplicationController
def index
@collection = model_class.paginate(page: params[:page], per_page: @per_page || 50) # I want this per_page value to come from the child controller, or use 50 if it's not set
end
private
def model_class
@model_class ||= controller_name.classify.constantize
end
end
class ChildController < BaseController
end
Where in the ChildController
is it best to set the @per_page
value and how do I implement it? I will have lots of child controllers, so I'm looking for the most straight forward way.
My only thought is to change it from @per_page
to per_page
, and then define this method in each child controller:
def per_page
20 # Or whatever value is needed for that controller
end
I suppose then I would need to also define this method in the parent controller to provide the default, so that would look like this:
class BaseController < ApplicationController
def index
@collection = model_class.paginate(page: params[:page], per_page: per_page) # I want this per_page value to come from the child controller, or use 50 if it's not set
end
private
def per_page
50
end
def model_class
@model_class ||= controller_name.classify.constantize
end
end
class ChildController < BaseController
private
def per_page
20
end
end
Is there a better pattern for this?
Upvotes: 1
Views: 531
Reputation: 1013
A little late to answer but I've been doing something similar in my app. If you're using will_paginate gem, just create an initializer for it named will_paginate.rb and put the following line in it:
WillPaginate.per_page = 50
The same approach is also mentioned in the Wiki for the gem. If you want to override this default, just do the customization in your model and not your controller. The model level setting will happen in the model.rb file as below:
self.per_page = 10
Now, It'll use the global settings when the model specific setting is not present.
Upvotes: 0
Reputation: 308
You can write a module and use class method to set per_page
just like code below:
controllers/concerns/paginate_concern.rb
require 'active_support/concern'
module PaginateConcern
extend ActiveSupport::Concern
included do
set_per_page 50 # default 50
end
class_methods do
def set_per_page(value)
append_before_action {
@per_page = value
}
end
end
end
base_controller.rb
class BaseController < ApplicationController
include PaginateConcern
end
child_controller.rb
class ChildController < BaseController
set_per_page 20 # override 50 to 20
def index
@children = Children.paginate(page: params[:page], per_page: @per_page)
end
end
Upvotes: 0
Reputation: 76774
If you wanted to set a "default" in the controller itself (I don't see any context as to which pagination gem you're using), you could use a class variable:
#app/controllers/base_controller.rb
class BaseController < ApplicationController
@@per_page = 50
end
This will set a class variable (different than an instance variable in that it's available whether the class has been invoked or not). This value will act as the default which you can build upon:
#app/controllers/child_controller.rb
class ChildController < BaseController
private
def per_page
@@per_page || 20 #-> if the "default" is not set, put it to 20
end
end
--
If you were using will_paginate
- or I think kaminari
does this too - you can set the per_page
default in the config of your application before the entire app loads:
#config/application.rb
...
WillPaginate.per_page = 50
Kaminari is similar, although I've lost the code right now.
Upvotes: 1
Reputation: 782
You can add it on your Rails application secrets and use it everytime you need that value, that is if that value is not going to change dynamically.
Once I created a table in the db called app_configurations where I stored all of this values. This is only recommended if you let the client change the values in an admin page or something (so he doesn't bother you often with such little changes)
If you consider those option bad, you can create a Ruby module with the methods you want and include it in your controller of wherever you want:
module Pagination
def per_page
50
end
end
And then
include Pagination
Upvotes: 1