Create an action with a class method in Rails - ruby-on-rails

I would like to create a custom action inside a controller with a class method. But is it possible ?
I would look like:
class HellosController < ActionController::Base
def self.index
end
end
The problem then is that, how can we access it... I tried this:
get 'hello/' => 'hellos.index'
But it's not a success.
ArgumentError: Missing :action key on routes definition, please check your routes.
I know it is not from the Rails conventions, but if you have some ideas, you're welcome.

Seems like a bad idea, or at least unconventional, to use a class method this way in a controller, but you could try something like this ..
class HellosController < ActionController::Base
def self.index
end
def index
self.class.index
end
end
Don't say I didn't warn you when you try to start using instance variables :)

Related

How to use decorator in rails correctly?

I'm newbie in using decorators and I need your help to understand how to use it right and what am I doing wrong.
book_decorator.rb
class BookDecorator < ApplicationDecorator
delegate_all
def in_users_list?(user)
if user.books.exists?
true
end
end
end
views/books/index.html.slim
- if book.in_users_list?(current_user)
- button_text = 'I've read this book'
... #depict some buttons and links
books_controller.rb
class BooksController < ApplicationController
expose(:book, attributes: :book_params, finder_parameter: :id)
expose_decorated(:book, decorator: BookDecorator)
...
I've followed these tutorials (https://github.com/netguru/decent_decoration https://github.com/drapergem/draper#decorating-objects) and it seems to be fine, but when i'm on books index page, it says
undefined method `in_users_list?' for Book:0x007f6f4a0a4a18
I suppose that it still doesn't know that it should use method from decorator, but how to fix it? I can't understand what I've done wrong, please help to find and fix problem!
Thank you in advance!
Well, I just had to add expose_decorated(:books) in books_controller. I thing that it's because I'm using it in index method, so books (not just book) should be decorated

Rails 4 execute associated model method from controller

Let say we have a code:
Model:
class Dog < ActiveRecord::Base
def self.make_noise
puts 'bow-wow'
end
end
Controller:
class DogsController < ApplicationController
def index
Dog.make_noise
end
end
This will work, but I would rather like to write the controller index method code like: AssociatedModel.make_noise or Model.make_noise
Is it possible in Rails to call associated model method without using its class name in code?
This would be useful if I would like to use inheritance and make let say PetsController which will be the base for all pets (or a PetNoise Concern included for every applicable controller) and declare there index method.
I'm not sure if I explained this well enough.
OK. The one way (which i don't like) is to write PetsController method like this:
def index
params[:controller].classify.constantize.make_noise
end
This way if I inherit PetsController from DogsController it will still work without defining separate index inside DogsController. But maybe there are other more neat solutions.
As I also explained in this answer, you can determine the model using params[:controller]. Like this:
params[:controller] # => "dogs"
params[:controller].classify # => "Dog"
Therefore you can write your index action "generically" like this:
def index
model_class = params[:controller].classify.constantize
model_class.make_noise
end

Rails: How to POST internally to another controller action?

This is going to sound strange, but hear me out...I need to be able to make the equivalent of a POST request to one of my other controllers. The SimpleController is basically a simplified version of a more verbose controller. How can I do this appropriately?
class VerboseController < ApplicationController
def create
# lots of required params
end
end
class SimpleController < ApplicationController
def create
# prepare the params required for VerboseController.create
# now call the VerboseController.create with the new params
end
end
Maybe I am over-thinking this, but I don't know how to do this.
Inter-controller communication in a Rails app (or any web app following the same model-adapter-view pattern for that matter) is something you should actively avoid. When you are tempted to do so consider it a sign that you are fighting the patterns and framework your app is built on and that you are relying on logic has been implemented at the wrong layer of your application.
As #ismaelga suggested in a comment; both controllers should invoke some common component to handle this shared behavior and keep your controllers "skinny". In Rails that's often a method on a model object, especially for the sort of creation behavior you seem to be worried about in this case.
You shouldn't be doing this. Are you creating a model? Then having two class methods on the model would be much better. It also separates the code much better. Then you can use the methods not only in controllers but also background jobs (etc.) in the future.
For example if you're creating a Person:
class VerboseController < ApplicationController
def create
Person.verbose_create(params)
end
end
class SimpleController < ApplicationController
def create
Person.simple_create(params)
end
end
Then in the Person-model you could go like this:
class Person
def self.verbose_create(options)
# ... do the creating stuff here
end
def self.simple_create(options)
# Prepare the options as you were trying to do in the controller...
prepared_options = options.merge(some: "option")
# ... and pass them to the verbose_create method
verbose_create(prepared_options)
end
end
I hope this can help a little. :-)

How can I perform another action of another controller (rendering too) in Rails 2.3.5 without a redirect?

I know that it's totally against the MVC, but anyway it must be done that way. So I need something like that:
app/controllers/controller_a.rb
class ControllerA < ApplicationController
def index
some_code
end
end
app/controllers/controller_b.rb
class ControllerB < ApplicationController
def other_index
#var = 'example'
end
end
app/views/controller_b/other_index.html.erb
<%= #var %>
So, when I visit the URL localhost:3000/controller_as/index (I mean, the one that corresponds the index action of controller_a.rb) I must obtain the next in my browser:
example
I mean, I must perform controller_b other_index action and render other_index.html.erb
I'll appreciate any help. Thanks.
You need to refactor the logic of controller_b into the model. Alternative would be to use AJAX to call controller_b from the index page of controller_a

How can I programatically determine which methods have been declared as "helper" methods by a controller in Rails?

I'm writing a plugin that adds a method to controllers and declares it as a helper method. If it were done statically (rather than through the plugin), it would look something like this:
# in RAILS_ROOT/app/controllers/stuffed_animals_controller.rb
class StuffedAnimalsController < ActionController::Base
private
def bear
'Teddy Bear'
end
helper_method :bear
end
# in RAILS_ROOT/app/views/stuffed_animals/index.html.erb:
<%= bear -%>
It works just fine. I want to test that :some_helper_method is actually a helper method, though. I tried this:
def test_declared_bear_as_helper_method
assert StuffedAnimalsController.helper_methods.include?(:bear)
end
Unfortunately, ActionController::Base does not have a :helper_methods class method. Anyone know where I can get the list of things a class exposes via :helper_method?
Got it!
def test_declared_bear_as_helper_method
helper = Object.new
helper.extend StuffedAnimalsController.master_helper_module
assert helper.respond_to?(:bear)
end

Resources