Call inner controller actions and send params between them rails - ruby-on-rails

I'm creating an API and I want that the outside can only has access to update method to actualize a report. But in case there is no report I want to create it. I know that the easy way to do it is just create it inside update method, but as soon I have already a create method build I was wondering if is it possible to call it sending it also some params.
I looked around like here Rails 3: Call functions inside controllers or the API but I didn't found any good solution.
Does anyone has a better one?
Thank you very much in advance.

You should not call an action of your controller from another action.
Why? Because every action of a controller is defined to respond to a request, which has several attributes (such as IP, params, session, HTTP headers, etc.). Imagine how "weird" it would be to call an action from another in the Controller.
If you want to do "extra logic" which would not be related to the update action (for example, create), you should call a protected (accessible only via the Controller & its children) method of this controller.
In your case, you could do something like this:
class ReportsController < ApplicationController
def update
#report = Report.where(id: params[:report_id]).first
if #report.nil?
create_report(params)
else
# etc.
end
end
protected
def create_report(params)
Report.create(params)
end
end

Related

At what point does a controller class instantiate a controller object in a Rails web app?

Learning Rails, the point at which a controller gets instantiated is unclear to me whereas, the point at which a model gets instantiated is somewhat recognizable as for example, when a user enters data in a from and clicks the submit button is sort of a trigger that leads to a creation of an object model.
Done some research and I'm visualizing in my head that when a HTTP request is sent via the browser, the routing to a controller becomes the trigger to instantiate a certain controller object from a controller class.
Is this somewhat correct?
When the HTTP request enters your application server (puma, webrick, etc), the request passes through a stack of middleware (defined in rails gem), which converts the HTTP request into an instance of ActionDispatch::Request class which is used to determine the correct route to dispatch to appropriate controller class in your rails app based on the route definitions defined in config/routes.rb.
The generated request object is then dispatched to the corresponding controller and action method which instantiates the Controller class and invokes an action method on it's instance with an argument of params object (instance of ActionController::Parameters).
This is just a general overview of how Controllers are instantiated. The request object passes through a series of middleware classes and modules before a request object is generated.
Here's a good article if you want to read it in detail.
As we define the routes in routes.rb, than the control goes to that controller action at that time the controller get's initiated to work
It is more related to object oriented programming, The object is always instantiated when you call new on class
2.0.0-p648 :001 > Class.new
=> #<Class:0x007fee8e99d9a8>
2.0.0-p648 :002 >
Here the object is instantiated, and similarly in rails when you call any action lets say
def new
#article = Article.new
end
new object gets initiated, when you click on save, you are actually calling create action, and pass the current object.
def create
#article = Article.create(article_params)
#article.save
end
here .create method filled object with article_params and .save method saves object in database.

I need a button or a link which runs method from my model

I can create method in a controller and add routes for it. After that I'll be able to use it like that <%= link_to "+", upvote_item_path(i) %>, but now my methods are in the model.
How can I use them?
Should I create *.js.erb and write a function which runs by the button with onclick or there is another way?
I can create method in a controller and add routes for it
That is exactly how you invoke methods on your models. Your app needs to provide a route, controller and action which invokes methods on your models on behalf of the user.
Buttons and links have absolutely no direct access to your model layer. Your model layer and the client can never communicate directly. The client submits requests, which are routed to an action on a controller, and that action may manipulate your models in some way, and then render a result. Trying to allow clients to invoke methods on your model layer without going through an action is absolutely incorrect, and not at all supported by Rails.

Middle man controller for Rails

I have two application controllers for my app. One that holds all my internal information and checks to see if users are logged in.
The other application controller is under a namespace called external.
This controller allows users to go to certain urls with a token, and the token represents a company that gets validated to see if the token belongs to a company. This way a user doesn't need to be logged it, they just need to know their uniq token.
The problem that I am facing is that there are autocomplete methods that I want to reuse that belong to my main application controller, but this controller checks to see if users are logged in so I get a 401 if I try to search on the external side.
I know there is no double inheritance in rails, but is there a way to kind of get a controller to belong to two different controllers? That way I can stick all my auto complete methods in this controller and both my Application controllers will be able to have access to it.
The main reason why I want to keep the auto complete methods in a controllers is so that I can make routes to them and have the actions return JSON so that JQuery autocomplete can use this information.
Thank you guys in advance, and if I am thinking about this wrong, please let me know and any other ideas you may have to accomplish this.
You can accomplish this by creating a module with your auto complete methods (and whatever other methods you want to share between controllers) and include the module in the appropriate controllers.
module ModuleName
def some_method
...
end
...
end
in the controller:
class ControllerName < ApplicationController
include ModuleName
...
end
some_method will be available in ControllerName and any other controller that includes the module

Performing AJAX calls on the "new" controller

In my rails app, I want to have a sortable list as part of an object creation. The best practice suggested in Railscast adds the acts_as_list plugin and then initiates AJAX calls to update item position. However, AJAX calls won't work on an unsaved model, which is the situation with new.
One solution would be to save the model immediately on new and redirect to edit. This would have a nice side effect of persisting any change so the user could resume work should he be interrupted.
However, this solution adds the unwanted complexity of saving an invalid model, compromising rails' validation processes. Is there any better way to allow AJAX + validations without going into too much work?
Your new action has the same access to parameters that any other action has. You could pass parameters for the unsaved object back to the new action and an object re-initialized with attributes set could be returned back to the view. For instance:
controller:
class WidgetsController < ApplicationController
def new
#widget = params.has_key?(:widget) ? Widget.new(params[:widget]) : Widget.new
end
..
end
Then in your view you'd have to send params to the new action via a link or a form post.
you can temporary store unsaved object in a 'session'.
like (this code must be in controller)
my_model = MyModel.new(params[:my_model])
session[:my_model_tmp] = my_model

Guidelines for calling controller methods in helper modules?

Few questions:
Is it possible to call a controller method in a helper module (e.g., application helper)?
If so, how does the helper handle the rendering of views? Ignore it?
In what instances would you want to call a controller method from a helper? Is it bad practice?
Do you have any sample code where you're calling controller methods in helper?
You generally don't call controller-methods from helpers. That is: if you mean a method that collects data and then renders a view (any other method that needs to be called should probably not be in a controller).
It is definitely bad practice and breaks MVC.
It is, however, perfectly possible to make controller-methods available in the views, a great example is for instance the current_user method.
To make a controller method available in the views, as a helper method, just do
private
def current_user
# do something sensible here
#current_user ||= session[:user]
end
helper_method :current_user
Such a method is best defined in the private section, or it could be available as an action (if you a wildcard in your routing).
Declare your methods on the corresponding controller
private
def method_name1
...
end
def method_name2
...
end
In the head of the controller declare
helper_method :method_name1, :method_name2
You may want to declare those methods under private state
And that's it, now you can use your method on a helper
Calling a controller from a helper violates the MVC pattern. IMO if you need to call a controller from a Rails view helper (like application_helper) then there is something about the design that could be improved. The intention is that helpers "help" views, and therefore only talk to models.
I'm not going to defend MVC itself here (there are a ton of references on the web), but this SO thread about calling the controller from a view should get you started.
Calling controller from view? (note, this is an ASP.NET thread, so only the high level principles are relevant).

Resources