I have a Rails engine and have the following in the {Rails_engine}/lib/role_authorization/session_user.rb
module RoleAuthorization
class SessionUser
mattr_accessor :current_user, :role
def current_user(user)
current_user = user
end
def roles(role)
role = roles
end
end
end
I am calling the following methods from the main_application
{main_app}/errors/application_errors.rb
class ApplicationErrors
def self.access_denied error, controller
RoleAuthorization::SessionUser.current_user(current_user)
end
However i am getting an undefined method current_user here . Does anybody have any idea what i am doing here
RoleAuthorization::SessionUser.current_user
Is undefined because you defined current_user as an instance method on the SessionUser class. Without knowing exactly how you're using this class in the rest of the system these following suggestions could work but break something else:
RoleAuthorization::SessionUser.new.current_user(current_user)
or add self to the method declaration in SessionUser:
module RoleAuthorization
class SessionUser
class << self
attr_accessor :current_user, :role
def current_user(user = nil)
self.current_user ||= user
end
end
end
end
Notice I changed mattr_accessor to attr_accessor. This is because the former is for Modules only and you're calling it within a class. Then I open up the singleton class with class << self so I can define current_user as a class method and use attr_accessor to access class instance variables. Assigning user to self.current_user will now make it available for access via: RoleAuthorization::SessionUser.current_user
Related
I am trying to access Devise's current_user variable inside a new instance of another controller. Here is my definition of GetsInterfaceController
class GetsInterfaceController < ApplicationController
def select_current_signed_in_user
#signed_in_user_here = current_user
end
end
Then I instantiate a new instance of GetsInterfaceController in ClientsController
class ClientsController < ApplicationController
def get_current_user
#gets_interface_controller = GetsInterfaceController.new
find_signed_in_user = #gets_interface_controller.select_current_signed_in_user
end
end
But I get null error on the #signed_in_user_here = current_user line in GetsInterfaceController when I try this. Anyway to get to the current_user attribute from inside GetsInterfaceController ?
I solved this by moving my code into a Module in lib directory. Works like a charm
current_user is not a variable - it is a helper method. Thus it is already available in all your helpers and views.
Additionally you never instantiate controllers in Rails. The router does that for you.
The only public methods in your controllers should be the actions which respond to HTTP requests.
If you want to reuse a method in several controllers you should be using inheritance, modules (concerns) or helpers. Never by calling a method on another controller.
To call an external service you want to create an API client class:
# adapted from https://github.com/jnunemaker/httparty
require 'httparty'
class StackExchangeClient
include HTTParty
base_uri 'api.stackexchange.com'
def initialize(service, page, user = nil)
#user = user
#options = { query: {site: service, page: page} }
end
def questions
self.class.get("/2.2/questions", #options)
end
def users
self.class.get("/2.2/users", #options)
end
end
Or if you need to call an external service and for example create several models with the data a Service Object:
class SomeService
def initialize(user, client: SomeClient)
#user = user
#client = client # for mocking
end
def call
response = #client.get('/foo')
response.each do |d|
#user.baz << d[:woo]
end
end
end
SomeService.new(current_user).call
I'm using Devise and Rails 3.2.16. I want to automatically insert who created a record and who updated a record. So I have something like this in models:
before_create :insert_created_by
before_update :insert_updated_by
private
def insert_created_by
self.created_by_id = current_user.id
end
def insert_updated_by
self.updated_by_id = current_user.id
end
Problem is that I get the error undefined local variable or method 'current_user' because current_user is not visible in a callback. How can I automatically insert who created and updated this record?
If there's an easy way to do it in Rails 4.x I'll make the migration.
Editing #HarsHarl's answer would probably have made more sense since this answer is very much similar.
With the Thread.current[:current_user] approach, you would have to make this call to set the User for every request. You've said that you don't like the idea of setting a variable for every single request that is only used so seldom; you could chose to use skip_before_filter to skip setting the User or instead of placing the before_filter in the ApplicationController set it in the controllers where you need the current_user.
A modular approach would be to move the setting of created_by_id and updated_by_id to a concern and include it in models you need to use.
Auditable module:
# app/models/concerns/auditable.rb
module Auditable
extend ActiveSupport::Concern
included do
# Assigns created_by_id and updated_by_id upon included Class initialization
after_initialize :add_created_by_and_updated_by
# Updates updated_by_id for the current instance
after_save :update_updated_by
end
private
def add_created_by_and_updated_by
self.created_by_id ||= User.current.id if User.current
self.updated_by_id ||= User.current.id if User.current
end
# Updates current instance's updated_by_id if current_user is not nil and is not destroyed.
def update_updated_by
self.updated_by_id = User.current.id if User.current and not destroyed?
end
end
User Model:
#app/models/user.rb
class User < ActiveRecord::Base
...
def self.current=(user)
Thread.current[:current_user] = user
end
def self.current
Thread.current[:current_user]
end
...
end
Application Controller:
#app/controllers/application_controller
class ApplicationController < ActionController::Base
...
before_filter :authenticate_user!, :set_current_user
private
def set_current_user
User.current = current_user
end
end
Example Usage: Include auditable module in one of the models:
# app/models/foo.rb
class Foo < ActiveRecord::Base
include Auditable
...
end
Including Auditable concern in Foo model will assign created_by_id and updated_by_id to Foo's instance upon initialization so you have these attributes to use right after initialization, and they are persisted into the foos table on an after_save callback.
another approach is this
class User
class << self
def current_user=(user)
Thread.current[:current_user] = user
end
def current_user
Thread.current[:current_user]
end
end
end
class ApplicationController
before_filter :set_current_user
def set_current_user
User.current_user = current_user
end
end
current_user is not accessible from within model files in Rails, only controllers, views and helpers. Although , through class variable you can achieve that but this is not good approach so for that you can create two methods inside his model. When create action call from controller then send current user and field name to that model ex:
Contoller code
def create
your code goes here and after save then write
#model_instance.insert_created_by(current_user)
end
and in model write this method
def self.insert_created_by(user)
update_attributes(created_by_id: user.id)
end
same for other methods
just create an attribute accessor in the model and initialize it when your record is being saved in controller as below
# app/models/foo.rb
class Foo < ActiveRecord::Base
attr_accessor :current_user
before_create :insert_created_by
before_update :insert_updated_by
private
def insert_created_by
self.created_by_id = current_user.id
end
def insert_updated_by
self.updated_by_id = current_user.id
end
end
# app/controllers/foos_controller.rb
class FoosController < ApplicationController
def create
#foo = Foo.new(....)
#foo.current_user = current_user
#foo.save
end
end
Here's the code:
class SyncController < ApplicationController
def get_sync
#passed_ids = params[:ids].split(',')
#users = #passed_ids.collect{|id| User.find(id)}
#add the current user to the list
#users << current_user
#recommendations = get_recommendations(#users)
end
end
module SyncHelper
def get_recommendations(users)
users
end
end
I'm getting a can't find get_recommendations method error...
Your SyncHelper module needs to be included into your SyncController class. You can either add the line
include SyncHelper
in your class definition, or, if SyncHelper lives in the expected app/helpers file, you can use the rails helper method.
I'm new with RoR and I have a controller (UsersController) where I wish to verify the existence of a certain session before anything. Since the session verification code is the same for several methods and I don't want to repeat myself, I decided to make a new method in my controller to check the sessions:
class UsersController < ApplicationController
def index
end
def show
end
def new
if self.has_register_session?
# Does something
else
# Does something else
end
end
def edit
end
def create
end
def update
end
def destroy
end
def self.has_register_session?
# true or false
end
end
And when I run the page /users/new, I got this error:
undefined method `has_register_session?' for #<UsersController:0x1036d9b48>
Any idea?
self when you define the method refers to the UsersController class object, but within the instance method new, self refers to the instance of UsersController.
You can either make your method an instance method:
def has_register_session?
# code
end
You can then get rid of the self when calling has_register_session? in new as well.
Or call the method on the class:
if UsersController.has_register_session?
# code
end
instead of referencing UsersController explicitly you could do self.class.
Note that you likely want the first solution: making has_register_session? an instance method.
By doing def self.blah you've created a class method whereas you want an instance method.
You might also want to make the method protected - all public methods are exposed as actions by default.
I am trying to do a custom active record macro. But it right now seems impossible set an instance variable from within it's block.. here is what i am trying to do.
module ActiveRecord
class Base
def self.included(base)
base.class.send(:define_method, :my_macro) do |args|
# instance_variable_set for the model instance that has called this
# macro using args
end
end
end
end
i have tried class_eval, instance_eval.. but nothing seems to work or i don't how to use them.
Thanks in advance.
Edit: Let me try to explain better. I have a class method. An instance of the class calls this method. Now, this class method should instruct the instance to set an instance variable for itself.
Edit- this is how i want o use the macro
class MyModel < ActiveRecord::Base
my_macro(*args)
def after_initialize
# use the value set in the macro as #instance variable
end
end
Is this what you are thinking of:
class DynamicAdd
def add_method
self.class_eval do
attr_accessor :some_method
end
end
end
You can then do the following:
k = DynamicAdd.new
k.some_method = "hi"
should result in an undefined method error.
But,
k = DynamicAdd.new
k.add_method
k.some_method = "hi"
should work.
You can use this same format to define other types of methods besides attr_accessors as well:
class DynamicAdd
def add_method
self.class_eval do
def some_method
return "hi"
end
end
end
end
Hm.. Isn't included() a Module method? I don't think you can use that in a class like you have written. If you want to create a class method you can do
class Base
def self.my_method
end
or
class Base
class << self
def my_method
end
end
If all you want to do is to add an instance variable to an existing object, then you can use #instance_variable_set
class Base
class << self
def my_method(instance_of_base, value)
instance_of_base.instance_variable_set "#x", value
end
end
end
a = Base.new
a.class.send(:my_method, *[a,4])