How to call methods of another controller - ruby-on-rails

I need to call methods from another controller. What is the best way? For example:
catalogues_controller.rb
class Site::CataloguesController < ApplicationController
respond_to :js, :html
def index
produc_list # call method other controller
end
end
other_controller.rb
class OtherController < ApplicationController
respond_to :js, :html
def produc_list
myObj = Catalagues.find(params[:id])
render :json => myObj
end
end

You could implement a module, and include it in your Controller.
Let's call this module "Products Helper":
# In your app/helpers
# create a file products_helper.rb
module ProductsHelper
def products_list(product_id)
catalague = Catalagues.where(id: product_id).first
render :json => catalague
end
end
And then, in the controllers you need to use this method:
class Site::CataloguesController < ApplicationController
include ProductsHelper
respond_to :js, :html
def index
products_list(your_id) # replace your_id with the corresponding variable
end
end

You can call dispatch directly on your controller's method. Pass in an ActionDispatch::Response instance and it will be populated with the response. Assuming a json response in this example:
def other_controller_method
req = ActionDispatch::Request.new(request.env)
resp = ActionDispatch::Response.new
YourControllerClass.dispatch(:your_controller_method_name, req, resp)
render json: resp.body, status: resp.status
end

If you have RESTful routes (and acccess to the helper methods that come with them), then you should just be able to use redirect_to to redirect to whatever action you want to call,
# something like... controller_name_action_name_url
# In your case, in the catalouges/index method
# Note this also assumes your controller is named 'other'
redirect_to others_product_list_url(product_id)

Related

Rails pass value/object/orm from parent controller to child

To keep to restfull protocol, I need to do /api/backup_jobs/777/errors.
In rails, the parent controller- I have:
module Api
class BackupJobsController < ApplicationController
respond_to :json
def show
#backup_job = #backup_jobs.find(params[:id])
respond_with data: #backup_job
end
end
end
in the child controller:
module Api
class ErrorsController < BackupJobsController
respond_to :json
def index
respond_with data: #backup_jobs.find(params[:id]).backup_events.errors
end
end
end
But obvisouley this isn't going to work because params[] doesn't exist for /api/backup_jobs/777/errors
How can I pass the #backup_job = #backup_jobs.find(params[:id]) from the parent controller's def show to the child controller and have it accessible in the child's def index?
You cannot do that because when an ErrorsController is created and used, you will not have a BackupsJobsController that ran before it.
This comes down to the nature of HTTP being a request-response protocol.
Instead, you can extract the line of code you wrote into a method that will be inherited by the ErrorsController.
backup_jobs_controller.rb:
module Api
class BackupJobsController < ApplicationController
def show
find_backup_job
respond_with data: #backup_job
end
protected
def find_backup_job
#backup_job = #backup_jobs.find(params[:id])
# or maybe #backup_job = BackupJob.find(params[:id])
end
end
end
errors_controller.rb:
module Api
class ErrorsController < BackupJobsController
respond_to :json
def index
respond_with data: find_backup_job.backup_events.errors
end
protected
def find_backup_job
#backup_job = BackupJob.find(params[:backup_job_id])
end
end
end

How to render json for all actions from the after_action filter in ApplicationController?

Is it possible to create an after_filter method in the Rails ApplicationController that runs on every action and renders to JSON? I'm scaffolding out an API, and I'd like to render output to JSON for every action in the controller.
clients_controller.rb
def index
#response = Client.all
end
application_controller.rb
...
after_action :render_json
def render_json
render json: #response
end
The after_action is never executed, and the code aborts with:
Template is missing. Missing template clients/index, ...
If the render json: #response is moved into the controller action, it works correctly.
Is there a filter that will allow me to DRY up the controllers and move the render calls to the base controller?
You can't render after_action/ after_filter. The callback after_action is for doing stuff after rendering. So rendering in after_action is too late.
But your exception is just because you miss the JSON template. I recommend using RABL (which offers a lot of flexibility to your JSON responses and there is also a Railscast about it). Then your controller could look like:
class ClientsController < ApplicationController
def index
#clients = Client.all
end
def show
#client = Client.find params[:id]
end
end
And don't forget to create your rabl templates.
e.g. clients/index.rabl:
collection #clients, :object_root => false
attributes :id
node(:fancy_client_name) { |attribute| attribute.client_method_generating_a_fancy_name }
But in the case you still want to be more declarative you can take advantage of the ActionController::MimeResponds.respond_to like:
class ClientsController < ApplicationController
respond_to :json, :html
def index
#clients = Client.all
respond_with(#clients)
end
def show
#client = Client.find params[:id]
respond_with(#client)
end
end
Btw. beware if you put code in an after_action, this will delay the whole request.

How to make Rails helper methods available when calling render_to_string to render a template

I have a ActiveMailer class, and inside I am sending emails with attached PDF template using the render_to_string method like this:
def send_sales_order(email_service)
#email_service = email_service
#sales_order = SalesOrder.find_by_cid(email_service.order[:id])
mail(:subject => I18n.t("custom_mailer.sales_order.subject", company_name: "test"), :to => #email_service.recipients) do |format|
format.html
format.pdf do
attachments['purchase_order.pdf'] = WickedPdf.new.pdf_from_string(
render_to_string('sales_orders/show.pdf.erb', locals: {current_company: #sales_order.company})
)
end
end
end
Inside the show.pdf.erb template, I called my helper methods defined elsewhere such as the current_company method defined in ApplicationController like follow:
class ApplicationController < ActionController::Base
helper_method :current_company, :current_role
def current_company
return if current_user.nil?
if session[:current_company_id].blank?
session[:current_company_id] = current_user.companies.first.id.to_s
end
#current_company ||= Company.find(session[:current_company_id])
end
But these helper methods are not available when I use the render_to_string method to render the template, is there a way around this?
Thanks
ApplicationController.new.render_to_string works for me
Starting with Rails 5 you can use:
rendered_string = ApplicationController.render(
template: 'invoice/show',
assigns: { invoice: invoice }
)
This create a request-like object in a controller like env, assign a #invoice instance variable accessible in the template.
See documentation here for more options:
http://api.rubyonrails.org/classes/ActionController/Renderer.html#method-i-render
Just beat my head on the wall for a couple hours on this one. Finally found the add_template_helper method which did the trick.
class ApplicationController < ActionController::Base
add_template_helper ApplicationHelper
...
def foo
#foo = render_to_string(partial: 'some_file.rb')
end
end
This will make all methods from ApplicationHelper available, even when using render_to_string with a partial.

How to write this rails library requiring respond_to and render?

I want to write this library that responds to some json and html request. In the controller's action, I will call MyLib.search(params). Then in "module Something; class MyLib", I have "def search(params); respond_to ... render :json ...; end". If I try to use this library, I get "NoMethodError (undefined method `respond_to' ...".
How should I write this, so that I get respond_to and render in scope?
Perhaps a mixin would serve you better, something like this:
module Something
def search # params will be in scope so no need to pass it
#...
respond_to do |format|
format.json ...
end
end
end
and then in the controller:
class SomeController < ApplicationController
include Something
def whatever
# ...
search
end
end

How do I use respond_with with custom classes in Rails 3?

I am making a JSON API with Rails and it seemed to work fine except for when I use respond_with custom classes (not an ActiveRecord inherited one).
Here is my class:
class JsonResponse
def initialize(data, status)
#data = data
#status = status
end
def as_json(options={})
{
:data => #data,
:status => #status
}
end
end
which is a simple response wrapper. When I try doing this:
def create
unless(Match.find_by_user_id(params[:user_id]))
Match.create(:user_id => params[:user_id])
end
time_response = JsonResponse.new("5", "success")
respond_with(time_response)
end
I get this error:
NoMethodError (undefined method `model_name' for JsonResponse:Class):
app/controllers/matches_controller.rb:9:in `create'
Any ideas? respond_with is driving me crazy.
Your class should response to to_json method
Obviously set :location option in respond_with method. Rails try to create restful route from the object you pass to the method, but because your object is not resource, the error is raised.
I am not sure if this helps but I do not see respond_to...
respond_with works together with respond_to...
respond_to :html, :xml, :json
This can be defined on Controller level
example:
class UsersController < ApplicationController::Base
respond_to :html, :xml, :json
def index
respond_with(#users = User.all)
end
def create
#user = User.create(params[:user])
respond_with(#user, :location => users_url)
end
end
and then you can define your json template... don't know if you leave the json template empty if it takes your "JSONResponse" class...
just a thought...

Resources