Call a method that is in my helper on rails 5 - ruby

I have this helper for a session in rails 5 and it's calling to the user table and then session table, that's because I have it related in my database, the code is the following one:
module SessionsHelper
def generate_user_session
session_build = user.sessions.build
session_build.generate_access_token
session_build.save!
end
end
The problem is when I called the method in a controller it appears this error:
undefined local variable or method 'user'
I know this error is due to I'm not referring well to my helper in my controller, the question is...
How is the correct form I can call a method from a helper in my controller?
Note: Consider that in my helper I'm calling to my table user that is also calling the table sessions.

You are trying to access a variable (user) that's only available on your controller. You may try to set and use #user as instance_variable.
But as tadman write, you shouldn't use helper to controller propose.
If it is for session proposes you could use a concern or create a new Class to deal with this.

Related

Ruby, Sinatra views and class methods

I'm learning how to use Sinatra. I figured out that when I pass object as locals, e.g.:
product = FetchProduct.new.call(id) #function finds exact Product instance
erb :"products/show", locals: { product: product }
I can use product object in my views with all instance methods I declared. But I can't use any class method, any attempt to do so gives me uninitialized constant error. What should I do if I want to use Product.format_price(product.price) method? Is there any way to pass class methods to Sinatra views?
klass = const_get( product.class )
klass.format_price
But that doesn't really make sense because you already know you want Product.format_price. So why don't you use Product.format_price?
It's generally a bad idea to run that kind of logic in your views. Best practice is to, wherever possible, serve to the view whatever it needs.
NB the reason you can't run the class method in your view is because Product is not accessible in your view and, to be honest, it shouldn't be if you want to follow MVC principles.
If it's just the format_price method you need in the view (especially since you seem to be passing an instance of Product into Product.format_price which is rather strange and a big code smell), then either create a helper method called format_price that is accessible by the view or, probably better, create a helper method called format_price in your controller (or in a helper module included in your controller) and pass the return value as a local i.e.
get '/' do
product = FetchProduct.new.call(id)
erb :'products/show', locals: {
product: product,
price: format_price(product)
}
end
private
def format_price(product)
# awesome formatting logic
end

Caching ActiveRecord model instance methods

Say I have a user model. It has an instance method called status. Status is not an association. It doesn't follow any active record pattern because it's a database already in production.
class User < ActiveRecord::Base
def status
Connection.where(machine_user_id: self.id).last
end
end
So I do this.
#users = User.all
First of all I can't eager load the status method.
#users.includes(:status).load
Second of all I can't cache that method within the array of users.
Rails.cache.write("user", #users)
The status method never gets called until the view layer it seems like.
What is the recommended way of caching this method.
Maybe this instance method is not what I want to do. I've looked at scope but it doesn't look like what I want to do.
Maybe I just need an association? Then I get the includes and I can cache.
But can associations handle complex logic. In this case the instance method is a simple query. What if I have complex logic in that instance method?
Thanks for any help.
Have You tried to encapsulate this logic inside some plain Ruby object like this (I wouldn't use this for very large sets though):
class UserStatuses
def self.users_and_statuses
Rails.cache.fetch "users_statuses", :expires_in => 30.minutes do
User.all.inject({}) {|hsh, u| hsh[u.id] = u.status; hsh }
end
end
end
After that You can use some helper method to access cached version
class User < ActiverRecord::Base
def cached_status
UserStatuses.users_and_statuses[id]
end
end
It doesn't solve Your eager loading problem, Rails doesn't have any cache warming up techniques built in. But by extracting like this, it's easily done by running rake task in Cron.
Also in this case I don't see any problems with using association. Rails associations allows You to submit different options including foreign and primary keys.

How to retrieve the controller class from within a view/helper in Rails 3?

I know about controller_name returning a string containing the controller's name but how can I retrieve the controller class (or object) from within a helper?
EDIT: The solution should also work when the controller is namespaced (eg. Admin::PostsController)
You can use the constantize method, like:
controller_name.constantize
Though I'm not sure how it will behave if you have a namespaced controller.
Update:
That one won't work for all controller names and/or namespaces. Though one can use the #controller method in combination with #class:
controller.class
A view probably shouldn't need to do this. Ideally whatever you're trying to do in the view that expects this, you would instead do in the controller.
Trying to think about why you'd want to do this, the best answer I can think of is that you want to invoke a helper method you've defined in the controller. There already exists a construct to do this, use helper_method.
For pretty much anything else, the controller should provide that data to the view. Not the view pulling it out of the controller. (e.g. even though you shouldn't need the class, the controller could provide it with #controller_class = self.class, which would then be available to the view)
In pure Ruby, because class names are constants, you can do this to get the class from a string:
classname = 'Posts'
p Kernel.const_get(classname).methods
There is a nice shortcut in Rails, constantize for just this:
p 'Posts'.constantize.methods
If the classname is eg 'editable_file', first call the camelize method:
p 'editable_file'.camelize.constantize # EditableFile
p 'extensions/editable_file'.camelize.constantize # Extensions::EditableFile
EDIT: If you really want to get the controller name un-demodulized, then this code in config/initializers/controller_name.rb should ensure it:
class ActionController::Metal
def self.controller_name
# #controller_name ||= self.name.demodulize.sub(/Controller$/, '').underscore
#controller_name ||= self.name.sub(/Controller$/, '').underscore
end
end

How to access Warden current user in business logic in Rails3

I am using Rails Warden plugin. It defines a helper method 'user' that returns current user. See the link for the source code.
Now I have an business logic object that does not have any reference to the controller. But I would like to get the current user. Is there any way of accessing this?
I have tried
ActionController::Base.helpers.user
or even
RailsWarden::Mixins::HelperMethods.user
with no luck. Thanks.
Now I have an business logic object
that does not have any reference to
the controller. But I would like to
get the current user. Is there any way
of accessing this?
So why can't you just pass the current user to those methods?
Additionally you can mix them in.
I strongly discourage you to write the static helpers (it is not Java, it is Ruby!).
Instead, where you need those helpers include them as a module:
module SuperLogic
def calculate_stuff(current_user=nil)
(current_user || user || self).bills.sum
end
edn
Then include this where you need it:
# user model
class User
include SuperLogic
#it will get the `calculate_stuff` method
end
# controller
include SuperLogic
# so you can use it as one of
calculate_stuff user
calculate_stuff
and so on...
additionally where you access your business logic, you can just create an instance of the class instead of "static" methods (in ruby they are "class" methods):
# controller
def calculate
#result = BusinessLogic.new(user).calculate_stuff
end
This is probably the easiest thing you can do.
Really, you don't need to access whole HTTP context in your business objects (I'm not even talking about testing it).
The way I think of business logic, it's something that sits between the controller and the model. I think it would be ok to pass an instance of the request to the logic methods, and since you're using warden, you can get the user from 'request.env['warden'].user'.
I haven't encountered a good reason not to have logic methods be static (self.) methods of a module. Maybe Dmytrii's suggestion works for you, but I prefer to 'require' than to dynamically include one-off logic bits.

Retaining Form data after POST in Ruby on Rails

I need to retain the Form data submitted in one view to be used in another view.
I'll be using POST method to submit the data. Is there anyway I can retrieve data from the POST method in Ruby, like in PHP I would use $title=$_POST["title"].
Any ideas?
Thanks and Cheers !
I think you just want the params hash? rubyonrails.org is down at the moment, but when it's back up take a read of the Action Controller Overview (or go to the google cache):
"Rails does not make any distinction between query string parameters and POST parameters, and both are available in the params hash in your controller"
For this, you need to understand the rationale behind the MVC pattern. Depending on whether or not you want to persist your data in the database, you derive your model-class from ActiveRecord, but as persistence seems not be context of your question, here is what you could try:
First, define a model like this
class Foo
# define variables here
attr_accessor :param1 # create reader and writer methods for param1
end
In your controller action:
def action1
#foo = new Foo
# pass parameters by using the params[] hash, e.g.
#foo.param1 = params[:param1]
end
You can then access the #foo object from every other view in your controller.
BTW, just found this screencast around the topic, #193 from railscasts.

Resources