Rails - How to access a Request Parameter from view in a helper - ruby-on-rails

How do you access a view's request parameter inside a Helper?
My view events/index7 sets the parameter date_selected:
<div><%= link_to 'View' , events_index7_path(:date_selected => date), :class => 'btn btn-mini'%></div>
My helper is app/helpers/calendar_helper.rb
Here's a pic of it at the point in the Helper I where I want to access it.
I tried this:
classes << "dayselect" if day == DateTime.strptime(params[:date_selected], "%Y-%m-%d")
I get this error:
undefined local variable or method `params' for #<CalendarHelper::Calendar:0x007f8d215671f0>
OR should I be passing the date to the helper in a different way?
Thanks for the help!

params is a controller method, belongs to ActionController:Metal http://api.rubyonrails.org/classes/ActionController/Metal.html#method-i-params
It's possible to let View to touch params by exposing this controller method as a helper.
class FooController < ApplicationController
helper_method :params
Then, in your view you can call this helper with params as argument. my_helper(params)
But, wait, this breaks MVC principle. View should not touch params at all. All these works should be done at controller level. What if the params is incorrect? You need controller to respond that, instead of passing that responsibility to view.
So, if you need to touch it in view, it's a smell. Review the whole process, there must be a better arrangement.

Related

Using helper methods in views

I'm having some trouble realising how the helper methods should be used in views. For example, take these parts of code:
Mycontrollers_helper.rb
module MycontrollersHelper
def destroy_everything
Model.destroy_all
redirect_to root_path
end
end
How should it be used in the view then ? Let's say adding the method to a button in the view:
<%= button_to 'Destroy all', destroy_everything, method => :post %>
Is just writing a method in the helper.rb file enough or does it require some additional lines in the controller it refers to ? Is this even the correct syntax for something like this ?
Helpers in rails actually view helpers. So they are meant to provide some help to render your views.
If you want to delete something, and then redirect to some action, just use a controller action for that.
I think you are taking about view helper, which you want to call from your view template.
You can call your view helper with the name of the method.
Calling destroy_everything will works fine if this helper is included in your controller.
Update:
If you write your helper method in application helper then you don't need to worry about load/ include the helper.

Get controller with a path

At this time i'm trying to get the controller with a path as a parameter
Then what I need is a method that returns the controller, something like
<%= get_controller(users_path) %>
Thanks
Let me introduce you to ActionDispatch's recognize_path:
Rails.application.routes.recognize_path(users_path)[:controller]
=> "users"
Please note that if you are outside a controller or view (such as in a model or in the console, for example), you need to first include Rails.application.routes.url_helpers before passing named helpers to the method. String routes ("/users" in this case) will work in any case.

Can't call instance method from index view

I'm trying to call method (instance method) which I have defined in the controller from the index.html.erb view.
records_controller.rb:
def calc_cell_balance
4
end
index.html.erb:
<% #records.each do |r| %>
<%= r.calc_cell_balance %><br>
<% end %>
I get this error:
undefined method `calc_cell_balance' for #<Record:0x35d18d8>
I don't want to make it a class method because it's bad design.
If I put the method definition in record.rb (the model), it's working.
I'm not sure what I'm doing wrong, since it's wrong to access the model from the view, but it's the only thing working.
How can I resolve this?
Thanks.
You put an instance method in your controller, RecordsController, but you are trying to call the method on an instance of the Record class. This doesn't make sense at all. Your #records are all Record instances. You would have to do something like:
RecordsController.new.calc_cell_balance
BUT DON'T DO THAT! Your controller is there to just direct what needs to be done, and shouldn't have methods that are called outside of the controller instance itself.
Your method probably belongs in the Record model, or maybe in a helper. It is not at all wrong to access the model from the view. That's the main thing that people do. If you really wanted to not be calling any methods from the view, you could try to gather up all the information in the controller like this:
#records = Record.all
#records_calc_cell_balance = #records.collect(&:calc_cell_balance)
And then you have parallel arrays of data, but that's just silly. Calling model methods from the view is fine. Or, if you feel the method is too view-centric (like maybe you want a method to tell you what CSS class to use), put that in a view helper, which is what it's for.

Use a params[:value] to reference a controller method in Rails

I currently have a form (using form_tag). One of the fields is a dropdown list of options. Each option value matches the name of a method in my controller. What I want to do is when the form submit button is clicked, it runs the controller method corresponding directly to the value selected in the dropdown field.
I've built a work-around right now, but it feels too verbose:
def run_reports
case params[:report_name]
when 'method_1' then method_1
when 'method_2' then method_2
when 'method_3' then method_3
when 'method_4' then method_4
else method_1
end
# each method matches a method already defined in the controller
# (i.e. method_1 is an existing method)
I had thought that it may work to use the dropdown option value to run the corresponding method in my controller through the form_tag action (i.e. :action => params[:report_name]), but this doesn't work because the action in the form needs to be set before the params value is set. I don't want to use javascript for this functionality.
Here is my form:
<%= form_tag("../reports/run_reports", :method => "get") do %>
<%= select_tag :report_name, options_for_select([['-- Please Select --',nil],['Option 1','method_1'], ['Option 2','method_2'], ['Option 3','method_3'], ['Option 4','method_4']]) %>
<%= submit_tag "Run Report" %>
<% end %>
Any suggestions?
Can I change my controller method to look something like this - but to actually call the controller method to run? I'm guessing this won't run because the params value is returned as a string...
def run_reports
params[:report_name]
end
WARNING: this is a terrible idea
You could call the method via a snippet of code like this in the controller:
send(params[:report_name].to_sym)
The reason this is a terrible idea is that anyone accessing the page could manually construct a request to call any method at all by injecting a request to call something hazardous. You really, really do not want to do this. You're better off setting up something to dynamically call known, trusted methods in your form.
I think you should rethink the design of your application (based on the little I know about it). You have a controller responsible for running reports, which it really shouldn't be. The controllers are to manage the connection between the web server and the rest of your app.
One solution would be to write a new class called ReportGenerator that would run the report and hand the result back to the controller, which would run any of the possible reports through a single action (for instance, show). If you need variable views you can use partials corresponding to the different kinds of reports.
As for the ReportGenerator, you'll need to be a little creative. It's entirely possible the best solution will be to have an individual class to generate each report type.

How to call a controller's method from a view?

I'm developing a small application in Ruby-On-Rails. I want to call a controller's method from a view. This method will only perform some inserts in the database tables. What's the correct way to do this? I've tried something like this but apparently the method code is not executed:
<%= link_to 'Join', method: join_event %>
The method option in a link_to method call is actually the HTTP method, not the name of the action. It's useful for when passing the HTTP Delete option, since the RESTful routing uses the DELETE method to hit the destroy action.
What you need to do here, is setup a route for your action. Assuming it's called join_event, add the following to your routes.rb:
match '/join_event' => 'controllername#join_event', :as => 'join_event'
Be sure to change controllername to the name of the controller you are using. Then update your view as follows:
<%= link_to 'Join', join_event_path %>
The _path method is generated based on the as value in the routes file.
To organize your code, you might want to encapsulate the inserts into a static model method. So if you have a model called MyModel with a name column, you could do
class MyModel
# ...
def self.insert_examples
MyModel.create(:name => "test")
MyModel.create(:name => "test2")
MyModel.create(:name => "test3")
end
end
Then just execute it in your action via:
MyModel.insert_examples
In addition to agmcleod's answer, you can expose controller methods to the view with ActionController::Base::helper_method:
class EventsController < ApplicationController
helper_method :join_event
def join_event(event)
# ...
end
end
But in this case, I think you're best off following his advice and moving this method to the model layer, since it's interacting with the database.

Resources