How to call a controller method in an associated view file? - ruby-on-rails

I am trying to create a method in a controller file, and then call that method in the index.html.erb view file.
Here are both my index action and my custom method in the controller file:
def index
#mustdos = current_user.mustdos
end
def calculates_mustdos_days_left
((mustdo.created_at + 7.days - Time.now) / ( 60 * 60 * 24)).round
end
helper_method :calculates_mustdos_days_left
And here is the relevant code from my associated my index.html.erb file:
<% #mustdos.each do |mustdo| %>
<tr id="todo-<%= "#{mustdo.id}" %>">
<td><%= calculates_mustdos_days_left %></td>
</tr>
<% end %>
I am getting this error:
NameError in Mustdos#index
And it is referencing this line from my index.html.erb view file
<td><%= calculates_mustdos_days_left %></td>
How can I resolve this? Thanks.

In general, I try to leave my helper methods for when I need them to generate content/output for a view. When I want to calculate and return data regarding a particular Model instance, I either add that code to a Service or the model itself.
app/models/must_do.rb
def days_left
((self.created_at + 7.days - Time.now) / ( 60 * 60 * 24)).round
end
Then, in my view, it's easy to access this off the model's instance:
<% #mustdos.each do |mustdo| %>
<tr id="todo-<%= "#{mustdo.id}" %>">
<td><%= mustdo.days_left %></td>
</tr>
<% end %>
For me, this is a cleaner implementation of the desired behavior. Wanted to offer it as an alternative/additional approach to #IS04's answer.

you could try:
helper_method def calculates_mustdos_days_left(mustdo)
((mustdo.created_at + 7.days - Time.now) / ( 60 * 60 * 24)).round
end
and then in your view file:
<% #mustdos.each do |mustdo| %>
<tr id="todo-<%= "#{mustdo.id}" %>">
<td><%= calculates_mustdos_days_left(mustdo) %></td>
</tr>
<% end %>
but instead controller methods you should use helper methods, also if your method is more general (related to model) and doesn't depend from view, you could define it in your model as #craig.kaminsky written

You can't do it. You can't call methods outside of the controller action you are in in your view. If you have a piece of logic like that you should really try to get it into a model. In this case I would put this method in the mustdo model.
But in those cases where putting the logic into a model does not make sense you can use helper namespaces. It is sort of a miscellaneous drawer for methods that don't quite fit anywhere, like display logic. Helpers go in the app/helpers/ directory. By default there is a helper namespace file in there called application_helper.rb. Any method you put in there will be available in all your controllers and views.

Related

Implementing Decorators with Rails app

I'm trying to do something very simple with Decorators. I've never personally setup a decorator and I'm trying to spend a bit of time learning about it. Basically I'm trying to take an attribute of a table and build some view logic around it. Here is my code:
Pages Controller:
def dashboard
#assignments = current_account.assignments.all.decorate
#invitation = Invitation.new
end
dashboard decorator:
class AssignmentDecorator < Draper::Decorator
def status
if finished
"Finished"
else
"Waiting"
end
end
end
View table:
<tr class="assignment-rows">
<td><%= link_to assignment.name, account_assignment_path(assignment) %></td>
<td><%= assignment.assigned_workers %></td>
<td><%= assignment.status %></td>
</tr>
As you can see I'm trying to call my assignment method in the td there. but I'm getting this error when I try to render the dashboard:
Use:
#dashboard = Dashboard.find(dasboard_id).decorate
EDIT:
It looks like you want an assignment decorator instead of a dashboard decorator.
Generate a new one with Draper, and then:
#assignments = current_account.assignments.all.decorate

Conflicting View Logic

I have a show page where I need to both show the student's units and create a unit for them. However an error is being incurred when trying to do both.
In my controller
def show
#student = Student.find(params[:id])
#unit = #student.units.build
#units = #student.units
end
In my view
<%= simple_form_for #unit, url: student_units_path(#student) %>
# form...
<% end %>
<% #units.each do |unit| %>
<tr>
<td><%= unit.course %></td>
<td><%= unit.mailing_date.strftime('%m/%d/%y') %></td>
</tr>
<% end %>
The unit.course call works and any call that is only the first child of unit, however when I call a second method on unit I get this error:
undefined method `strftime' for nil:NilClass
despite knowing that the unit exists, hence the first call working
It seems your issue is that unit.mailing_date is nil, for newly-built records.
One solution would be to define a default value for mailing_date, either at the database level or in your application. For example, you could do something like:
class Unit < ActiveRecord::Base
# ....
after_initialize :set_default_mailing_date
private
def set_default_mailing_date
self.mailing_date ||= Date.today
end
end
Or alternatively, you could leave the mailing_date as nil and handle this gracefully in the view:
<td><%= unit.mailing_date.try!(:strftime, '%m/%d/%y') %></td>
If you are using ruby version 2.3+, then I would advise using the built-in safe navigation operator, rather than ActiveSupport's try! method:
<td><%= unit.mailing_date&.strftime('%m/%d/%y') %></td>
Finally, if you went with the above choice to leave the mailing_date as nil, then perhaps you'd like to display some default value in its place - for example:
<td><%= unit.mailing_date&.strftime('%m/%d/%y') || 'Not set' %></td>
As an alternative, I assume you don't want the new unit bound to the form being rendered which is what is causing the error.
You could do
#units = #student.units.reject(&:new_record?)
To remove the newly built unit from the collection

Controller and view association and self.method still confuses me

Okay so in the index portion of my controller I set
#patients = Patient.all
then in patients_helper.rb
def race_abrev
return self.caucasian
end
where caucasian is an integer datatype column in the patients table
then in the view index.html.erb
<% #patients.each do |p| %>
<td><%= p.gender %></td>
<td><%= p.ethnicity %></td>
<td><%= p.race_abrev %></td>
<% end %>
I get a
undefined method `race_abrev' for #<Patient:0xb4d95cd8>
I've checked the table and I'm expecting patient.caucasian to return the integer 1, what am I missing..any insight to a fundamental misunderstanding I seem to have?
race_abrev is a helper, not a method on Patient:
<%= race_abrev(p) %>
And the helper itself would return p.caucasian, although it'd seem like you'd actually want to do something with the value of caucasian, like a compare or something.
All this said, I'm not sure why you're not defining it (or what "it" actually is) on the model, since so far it doesn't seem to have anything to do with the view, which is what view helpers are for.
If you're storing something in the DB you want to transform it may or may not belong in a view helper; if it's to turn it into something human-readable I'd be more likely to put it in the model.

Create a class to populate page in ruby 1.8.7

I'm trying to make a class to populate a deals tab on my website.
Part 1. Take an items close date (CatalogItem.close_date) and use all items within 12 hours of closing. Part 2. Calculate the deal percentage by using the current price (CatalogItem.current_price) and estimated value (Item.estimated_price) <-- You'll notice they're in different tables but they're identified by an identical item_id.
I'm green in RoR, so I'm having trouble connecting this in a class, but I can make it work individually in the console:
hour_diff = (CatalogItem.last.close_date - Time.now) / 1.hour
deal_percentage = (CatalogItem.last.current_price.to_f / Item.last.estimated_price)*100
As you can see I'm using my .last piece of data, but I want to create an array that runs through all my items, that's where my knowledge goes dry, any help would be much apreciated
I'm assuming you are using a belongs_to, but I think what you want to do is use
an instance method. This would be your model, app/models/catalog_item.rb
class CatalogItem < ActiveRecord::Base
belongs_to :item
def hours_remaining
(close_date - Time.now) / 1.hour
end
def deal_percentage
(current_price.to_f / item.estimated_price)*100
end
end
Then, you could access them in a view something like this:
<table>
<% CatalogItem.all.each do |ci| %>
<tr>
<td><%= ci.hours_remaining %></td>
<td><%= ci.deal_percentage %></td>
</tr>
<% end %>
</table>

ruby on rails global method

I have a user controller which consists of a method named listfolders().
class UserController < ApplicationController
def myaccount()
userId = session[:id]
#listfolders = UsersFolders.listfolders(userId)
#users = User.listusers()
end
end
In the views I have and I'm able to fetch the folders:
<% #listfolders.each do |userfolder| %>
<tr>
<td><b><%= userfolder.foldername %></b></td>
</tr>
<% end %>
PROBLEM: I want to display the folders in all pages like compose,drafs,trash etc ... instead of just for the action.
How can I do it ?
The basic, standard way to do this would be in a helper.
module ApplicationHelper
def listfolders(user_id)
lf = UsersFolders.listfolders(user_id)
render 'users_folders/listfolders', :listfolders => lf
end
end
then in app/views/users_folders/_listfolders.html.erb
<% listfolders.each do |userfolder| %>
<tr>
<td><b><%= userfolder.foldername %></b></td>
</tr>
<% end %>
calling it is as easy as:
<% listfolders(session[:id]) %>
If I understand everything right you need some :before_filter in your controller to initialize #listfolders and #users variables
You can easily move the code to load the folder + the partial template to a cell component and then call that cell from any view.
Check this:
http://cells.rubyforge.org/
It will work just like the render :partial calls but will add a controller like process that should load the user folders and then will create the partial to be rendered.
The other approach that should work is to have a method on the application_controller to load the folders. Then add a before_filter calling that method to every action that should render the folders.
Finally you can create a shared partial to be rendered on each of the views that should be showing that.
Note: The method to load the folders can be defined in a more specific controller if you will only show the folders on actions from the same controller of for a child controller.

Resources