I just wrote a small module in my Rail 3.0.0 application lib folder:
module AdminFilters
def verify_is_admin
if current_user.nil? || current_user.role != User::Role::ADMIN
redirect_to :root, :alert => "You don't have enough permissions"
end
end
end
And in order to make it available for all my controllers :
class ApplicationController < ActionController::Base
protect_from_forgery
require "admin_filters"
include AdminFilters
end
If I remove the require line, rails complains like this :
uninitialized constant ApplicationController::AdminFilters
Is it the normal behavior ? I thought that any rb file in the lib folder was auto-loaded by rails ...
Yes, it was auto-loaded in Rails 2.x.x, but Rails 3 doesn't load files from lib/ anymore. You should consider placing your files into the config/initializers directory.
Related
I am returning to Rails after 5 years out of it and trying to understand the changes. I am going through Ryan Bates' Railscasts looking to update a template I built some years ago and am getting the above error when initializing the permissions class for authentication. (See RC#386 about 18:00 into the playback.)
Rails has changed the before_filter to before_action (makes sense...) and I have the following in the ApplicationController:
class ApplicationController < ActionController::Base
before_action :authorize
delegate :allow?, to: :current_permission
helper_method :allow?
delegate :allow_param?, to: :current_permission
helper_method :allow_param?
private
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
helper_method :current_user
def current_permission
#current_permission ||= Permissions.permission_for(current_user)
end
def current_resource
nil
end
def authorize
if current_permission.allow?(params[:controller], params[:action], current_resource)
current_permission.permit_params! params
else
redirect_to root_url, alert: "Not authorized."
end
end
end
My permissions.rb file has the following:
module Permissions
def self.permission_for(user)
if user.nil?
GuestPermission.new
elsif user.admin?
AdminPermission.new(user)
else
MemberPermission.new(user)
end
end
end
I'm getting the above error: NoMethodError at /undefined method "permission_for" for Permissions:Module from BetterErrors (and Puma). However the method should be defined in the Permissions module; it's right there. Yet somehow, something has changed in Rails that I can't figure out.
I have tried to require the file: nothing.
Any help?
You need to include a module in a class to use it. It then adds functionality to that class, you do not access methods in module itself.
I'm guessing you need to do something like this (not tested):
class ApplicationController < ActionController::Base
include Permissions
before_action :authorize
change your module to:
module Permissions
def permission_for(user)
...
and then permissions_for is available in your controller
def current_permission
#current_permission ||= permission_for(current_user)
end
The only thing that has changed in Rails is how folders and files are included. The lib folder inside your rails app is not autoloaded by default.
I think best practice is now to add a lib folder within the app folder and then put all your modules and other classes in there. They will be included as soon as you restart your server.
I have a nested module set up as a base helper method which is not getting included in the app that uses the engine.
in lib/mol/blog/blog.rb
require "mol/blog/engine"
module Mol
module Blog
module Categories
def self.included(base)
base.helper_method :categories
end
def categories
Mol::Cms::Category.all
end
end
end
end
In the engine's spec/dummy application_controller
class ApplicationController < ActionController::Base
protect_from_forgery
include Mol::Blog::Categories
end
This works fine and the categories appear as expected. However, when I try to use the engine in a different app, the Categories module is not being included.
in the app's application controller
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
include Mol::Blog::Categories
end
In the rails console, the error is uninitialized constant Mol::Blog::Category (NameError)
Mol::Blog is defined, no error or anything. Why is the Categories module not being recognised?
Your app does not know about Mol::Blog::Categories module. You should require it in the "mol/blog/engine.rb" file or in the "mol/blog.rb" file.
# mol/blog.rb
require "mol/blog/categories"
module Mol
module Blog
# ...
end
end
Rails 4.2.4, Ruby 2.1.7
I have a module inside lib/ directory.
lib/BLL/user_feed.rb
module BLL
class UserFeed
def initialize
logger.debug "Class has been initialized"
end
def get_user_feed(user_id)
# logic here
return {
# object
}
end
end
end
When I try to include that in my controller to use my user_Feed logic,
it's throwing
ActionController::RoutingError (uninitialized constant UserfeedController::BLL):
error.
I am not sure what's wrong.
class UserfeedController < ApplicationController
include BLL
before_action :authenticate_user!
def show
# some logic
end
end
Never version of Rails do not include the lib folder into the application's loadpath per default. To include the lib folder into the loadpath add the following to your config/application.rb:
config.autoload_paths << Rails.root.join('lib')
I have alredy 3 grey hair from this. Rails4.0/ruby 1.9.3. I have file test.rb in directory /lib/moduletest/test. test.rb looks like this:
module Moduletest
class test
end
end
How can I instantiate this class in my controller? How should I use the require command? Moduletest::test.new() ?
At first may I suggest you to use "foobar" instead of "test". "test" looks really like, test.
Back to question, there are two ways to use it in controller, given you have already loaded the module correctly as per comments.
The first is to explicitly include it. Preferred
class ApplicationController < ActionController::Base
include ModuleFoo
def index
bar # Use ModuleFoo's method directly
#...
end
end
The second is to hook the extension in Rails loading
# ModuleFoo
module ModuleFoo
def bar
end
end
if defined? ActionController::Base
ActionController::Base.class_eval do
include ModuleFoo
end
end
# Controller
class SomethingController < ApplicationController
def some_method
bar # use this directly
end
end
You have to put the lib directory into your autoload path. So Rails load your file on startup:
config/application.rb and add:
config.autoload_paths += %W(#{config.root}/lib)
I have a controller having more than 1000 lines of code.
Right not I am doing Code review for this controller.
I arrange my methods according to the module.
Now I realise that my controller is not easy to maintain and so I want to something like following
class UsersController < ApplicationController
#Code to require files here
#before filter code will goes here
#############Here i want to call that partial like things. following is just pseudo #########
history module
account module
calendar module
shipment module
payment module
####################################################################
end #end of class
this help me so much to maintained the code as when i change history module i am sure that my account module is unchanged.I know CVS but i prefer 50 copies of each module instead 200 copies of my users_controller.rb itself.
P.S. :- I would like Affirmative answer.please don't answer like, you should use different controller for different module.....bla...bla...bla... as it's not possible for me to do so.
EDIT:- My Versions Are
rails -v
Rails 2.3.4
ruby -v
ruby 1.8.6 (2008-08-11 patchlevel 287) [i386-linux]
This should work for you:
app/controllers/some_controller.rb
class SomeController < ApplicationController
include MyCustomMethods
end
lib/my_custom_methods.rb
module MyCustomMethods
def custom
render :text => "Rendered from a method included from a module!"
end
end
config/routes.rb
# For rails 3:
match '/cool' => "some#custom"
# For rails 2:
map.cool 'cool', :controller => "some", :action => "custom"
Fire up your app and hit http://localhost:3000/cool, and you'll get your custom method included from a module.
Assuming from you pseudocode that you are referring to Ruby modules, and not something else, just put all your requires/modules in a separate module and include that or have your UsersController inherit from a base class if you are reusing those files. In the first case you can think of a module as a mix-in and it is designed for exactly the modularity you want.
module AllMyStuff
include History
include Account
...
end
class UsersController < ApplicationController
include AllMyStuff
def new
end
...
end
or you can inherit from a base controller,in this case its probably a reasonable solution.
def BaseController < ActionController
include history
include account
end
def UsersController < BaseController
# modules available to this controller by inheritance
def new
end
...
end
I tried the following method and I have it running, maybe it suits for you:
app/user_controller.rb
require 'index.rb'
class UsersController < ApplicationController
# some other code
end
app/index.rb
class UsersController < ApplicationController
def index
#users = User.all
end
end
MY ENV: rails 3 beta4