undefined method `to_key' for -- NOT USING MONGO - ruby-on-rails

I found a gazillion answers for my issue if I was using Mongo, but none of the ones I see work out here since I am not using mongo.
Basically I have a report_controller.rb that has a very simple method defined:
def donations_by_season
#donations = Donation
end
and a very simple report/donations_by_season.html.erb as follows:
<%= form_for #donations do |f| %>
Stuff Will go here... such as fields to select a date for the season we wish to view.
<% end %>
There is no report model, just a controller and views.
But when I attempt to view /reports/donations_by_season
I immediately get:
undefined method to_key' for #<Class:0x00000114d85918>
What should I do to fix that? Am I doing my form incorrectly since there is no model associated with reports?

You should never be assigning an instance variable to point to a class object like this. You probably want this:
def donations_by_season
#donations = Donation.all
end
Note the .all versus just leaving it blank. You could also do .new or a litany of other methods, depending on what you're trying to do.

Related

How can I call a method on my form controller from my view in Rails?

Newbie to RoR. I can't grasp the concept of how to call a simple method on my form controller from my view. I want to collect 2 pieces of information form the view, call a method on the form controller that will retrieve a piece of information based on the parameters, and then display the piece of information on that same view or another one. Right now, I was trying to use a form controller instance variable to accomplish the displaying of the new piece of information--not sure how I will refresh the view to display it but that is a future hurdle. Right now, I can click my Submit button without getting any errors but it is clearly not hitting my form controller method.
Here is my erb file for the view:
<h1>Enter Required Information</h1>
<%= form_tag (get_hotel_recommendation_path) do %>
<%= label_tag(:name, "Name:") %>
<%= text_field_tag(:name) %>
<%= label_tag(:date, "Date (yyyy-mm-dd):") %>
<%= text_field_tag(:date) %>
<%= submit_tag("Submit") %><br><br>
<%= label_tag(:recommendation, "Recommendation:") %>
<%= #recommended_hotel_name %>
<% end %>
Here is my form controller code:
class RecommendHotelController < ApplicationController
#recommended_hotel_name = ''
def collect_info
end
def get_hotel_recommendation
#recommended_hotel_name = Member.recommended_hotel_name( params[:name], params[:date] )
end
end
I really just want a simple and easy way to do this--not necessarily the best. I just need a quick UI to demonstrate my model code. And I need to get it done soon.
New form controller code:
class RecommendHotelController < ApplicationController
def collect_info
end
def get_hotel_recommendation
redirect_to recommend_hotel_path
end
protected
helper_method :recommended_hotel_name
def recommended_hotel_name
unless (params[:name].nil?)
Member.recommended_hotel_name(params[:name], params[:date])
end
end
end
Once the controller hands over to the view, there's no going back to call additional methods. It is the controller's job to prepare everything the view might need in advance. Once inside the render phase, there's no way to call controller methods.
The exception to this is helper methods which can be called. You need to declare any methods you want to use within your view explicitly. As an example:
helper_method :get_hotel_recommendation
def get_hotel_recommendation
# ...
end
Helper methods can also be located inside the associated helper module, and it's a good idea to put them there if they're used exclusively within views.
In your case, if you're using this only once, you should probably skip the assignment to an instance variable and just return the object in question. The view would look like:
<%= recommended_hotel_name %>
The adjusted controller method:
class RecommendHotelController < ApplicationController
protected
helper_method :recommended_hotel_name
def recommended_hotel_name
Member.recommended_hotel_name(params[:name], params[:date])
end
end
It's worth noting that declaring #recommended_hotel_name = '' in the class context is probably not what you intend. This creates a class variable, not an instance variable. Instance variables in controllers must be defined inside the primary action method or inside a before_filter method. Also remember that instance variables are nil by default, so there's no need to initialize them to that first. An empty string and nil are equivalent when used within a view, everything inside <%= ... %> is converted to a string for you automatically.
Another thing to watch out for is leaving a space between a method name and its arguments. It should be form_tag(...) and not form_tag (...). Normally this does not make a difference, Ruby can be very lenient, but sometimes it can subtly alter the way the arguments are interpreted leading to a lot of confusion as you try to diagnose the problem. Stylistically speaking, only keywords like if, while and case have a space before the brackets as these are not method calls.
As to why your form isn't working, it's not clear. Those parameters should be submitted as you intend, but maybe you're not getting the right routing. Remember it's best to stick with the standard index, new, show, and edit names unless you're doing something exotic. In this case, you should probably define this as index if it shows more than one record or show if it's always one record.
You can get all the information from a form submit in the params array. However, from your example, I would advise to use: form_for instead of using separate form_tags.

Basic question on Ruby Rails

Suppose I have model xyz.rb and model abc.rb. No relation between them. If want to print any attribute from xyz in abc views/print/show.html.erb how??
I know very basic but looking for good explanation.
You can access any model from any controller, view or helper method. Mvc means model, controllers and views are related but there's no limitation on access between them. The normal thing to do would be to store the reports to an instance variable in any controller then output them in the view:
#print_controller.rb
def show
#reports = Report.find_by_some_attribute(...
#show.html.erb
<%- #reports.each do |report| -%>
<%= report.created_at -%>
<%- end -%>
I really think though that you need to find a better approach to learning rails. This is very basic like you say and I would recommend you buy a book. Do you speak English well, or what's your native language?
Something like:
XYZ.all.each do |xyz|
some(xyz)
end
Details you can find here.
Sure you can.
Assuming #x is an instance of Xyz model, you can do print any attribute of #x object.
If you dont have #x object. You can find it and instantiate #x in the show action of the abc controller. #x = Xyz.first for example.
Considering your example, if you have two models User and Report. You can access Report's created_at from User's controller,view,etc.
You need to write something like this:
Report.find_by_created_at("2013-11-12 14:43:44.11824")
You can refer ruby on rails guides to learn rails. Also you can find basic active record explanations here
This very basic but i am giving best solution to this
in abc controller
def show
#reports = Report.where(:attribute => value)
end
it will get the all records basic on that value
<h1>views/abc/show.html.erb</h1>
<% #reports.each do |report| %>
<%= report.attribute_name %>
<%end%>

Rails best practice to check an object's existence before displaying an attribute in a layout

I have the following code in a layout:
Posted <%=time_ago_in_words post.created_at %> ago
<% if post.has_tag != nil %>
in the <%= post.get_first_tag.name %> category
<% end %>
And the following code in the post model which is inheriting form ActiveRecord::Base
def has_tag
!self.tags.empty?
end
def get_first_tag
self.tags[0]
end
Tags is also inherited from ActiveRecord::Base and Post 'has_many' Tags
Firstly: Is this the best way of checking if the post object has at least 1 associate tag attribute.
Secondly: Should I be putting this logic into a helper method?
Thirdly: Why doesn't the following work (it returns a # where the tags should be):
in the <%= post.tags.to_sentence %> category,
I guess its because tags aren't actually stored as an array attribute, but i don't really know.
This is a perfectly good way of checking if there are tags or not. However, self.tags.empty? will return true or false so post.has_tag will never be nil.
It's worth noting that, in ruby, it is common to name methods that return true or false with a question mark. So post.has_tag? would be a better name for your method (like the empty? method for the tags).
This sort of method belongs in the model class rather than a helper as it is not specific to the view layer; you might want to call this method from other model classes, for example.
The reason you are getting # instead of your tag names is that you are trying to convert a collection of tags to a sentence and you need instead to convert the names of the tags to a sentence. You should be able to do
post.tags.map(&:name).to_sentence
which will take the names of the tags and turn them into a sentence.
For one thing, you probably need
<% if post.has_tag %>
instead of
<% if post.has_tag != nil %>
In your definition, has_tag should never return nil, and thus 'in the...' part will always be shown.
Generally, your idea seems fine to me: I often add helpers like these to models.

Can't display converted units in nested form

I'm working on an app where I have a user preference to show distances or weights in metric or standard units. I'm using a filter to save the units in a consistent format in the database
before_save :convert_distance
What's the best way to display these units in my views? I tried adding a getter in my model called display_distance like below, but it didn't work.
#model
def display_distance
self.workout.user.uses_metric ? self.distance * 1.609344 : self.distance
end
#view
<%= f.text_field :distance, {:value=>f.object.display_distance} %>
#error
You have a nil object when you didn't expect it!
I did a to_yaml and verified that f.object is an instance of the correct object. Also, I'm using nested forms, I'm not sure if that matters.
Also, I'm not sure if I should be trying to do the conversion in the model or in a helper. I thought the model would be better as I'll be using this functionality in multiple views.
The form does not know anything about your object, you have to pass it in through your controller. You likely have something like this in your controller (assuming this is the edit view):
def edit
#my_object = MyObject.find(params[:id])
end
Then you can access this in the view like so:
<%= #my_object.display_distance %>

DRYing my views, helper / method / something else?

Have written some RoR sites in the past, but never bothered too much at DRYing up my views as it's only ever been me looking at the code.
Just starting a new site, that is likely to be a collaboration, and need help
I call this line multiple times in my views, and from multiple places.
<%= Person.find_by_id(rider.person_id).name %>
I'd like to be able to just do
<%= get_name(rider.person_id) %>
So I'd assume I'd put this code somewhere
def get_name=(id)
Person.find_by_id(id).name
end
But where? I've tried in the model and as a helper, but always get nomethoderror.
You're wrong in naming this method.
Why you put "=" sign in the method name?
You should call this code only in controller, and in the views, only render result.
The best place for this method is a helper.
def get_person_name_by_id(id)
Person.find_by_id(id).name || nil
end
try application_controller.rb
How about a method on the Rider class that just returns the name?
def name
person = Person.find_by_id( #person_id )
if !person.nil?
return person.name
end
return nil
end
used as
<%= rider.name %>
or, you could use a static/class method on the Person class.
def Person.get_name( rider )
if !rider.nil?
person = find_by_id( rider.person_id )
if !person.nil?
return person.name
end
end
return nil
end
called as
<%= Person.get_name( rider ) %>
Note that I dropped the reference to the id in the view code.
Rails is all about convention over configuration. All of it's helper methods assume the most common options unless overridden. However ActiveRecord models don't have a useful default to_s.
Specifying the default action:
class Person < ActiveRecord::Base
def to_s
name
end
end
Now every time you try to evaluate a person instance in string context you'll get a name.
So
<%= Person.find_by_id(rider.person_id).name %>
Can now be replaced with
<%= rider.person %>
For anything else you can specify field and methods.

Resources