Not able to display hash on rails 3 - ruby

How to display value from Hash onto page
I have a hash in my User model class
GENDERS = {'1' => 'Male', '2' => 'Female', '3' => 'Secret'}
And i store the key for every user.
So when user read their info, i want to display corresponding value regarding to the key
So i am doing like this:
<td><%= User::GENDERS[#user.gender] %></td>
But i cannot see anything display.
if i do the following,i do see the right key display
<td><%= #user.gender %></td>
So, what is the right way to display a value from a hash onto page programatically?
Thanks.

Is the gender field a string or an integer? If it's an integer, you'll need to change the hash to:
GENDERS = {1 => 'Male', 2 => 'Female', 3 => 'Secret'}

Just note that this is not particularly good style. You should rather write a method within User.rb:
GENDERS = {1 => 'Male', 2 => 'Female', 3 => 'Secret'}
def gender_name
GENDERS[gender]
end
and then in your view call:
<td><%= #user.gender_name %></td>
That way you will not expose that much of your model in the views and keep everything transparent. It will also allow you to modify the display later if you want, without having to change the views.

use model's accessor that get corresponded to a constant gender

Related

The proper search result is not coming using Rails 3

I need to access all values from Database according to id but i am getting the following output.
Output:
all details are #<PaymentVendor:0x1ee5860>
all details are #<PaymentVendor:0x1f02798>
I am explaining my code below.
#rest_ids=[21,22,23]
#rest_ids.each do |ids|
#pdf_vendor_details = PaymentVendor.where(:id => ids )
puts "all details are #{#pdf_vendor_details}"
end
From the above code i have some array of ids(i.e- #rest_ids).Here my requirement is when the loop will execute as per id the record will fetch and store in the variable #pdf_vendor_details in array.If I wanted to display some value in table then i will be able to do that like below.
table.html.erb:
<table>
<tr>
<td>ID</td>
<td>Receipt No</td>
<td>Amount</td>
</tr>
<% #pdf_vendor_details.each do |details| %>
<tr>
<td><%= details.id %></td>
<td><%= details.Receipt_No %></td>
<td><%= details.Amount %></td>
</tr>
<% end %>
</table>
But doing this way i can not get any value and unable to display data in table.Please help me to access the data from DB which will store in array to display in table.
Try this:
#pdf_vendor_details = PaymentVendor.where(:id => #rest_ids ) #rails 4
#OR
#pdf_vendor_details = PaymentVendor.find_all_by_id(#rest_ids) #rails 3
#pdf_vendor_details.each do |pdf|
puts "all details are: ID => #{pdf.id}, Receipt_No => #{pdf.Receipt_No}, Amount=> #{pdf.Amount}"
end
Your table.html.erb will be not changed
You can try
PaymentVendor.where(id: [21, 22, 23])
which will build a SQL statement like
SELECT * FROM payment_vendors WHERE id IN (21, 22, 23)
I don't see any reason in looping #rest_ids and querying on each iteration
#pdf_vendor_details = PaymentVendor.where(:id => ids )
and in each iteration you are replacing the previous value of #pdf_vendor_details instead of appending to the array.
Instead
#pdf_vendor_details = PaymentVendor.where(id: #rest_ids ) #rails 4
or
#pdf_vendor_details = PaymentVendor.find_all_by_id(#rest_ids) #rails 3
will do. It will send one query to fetch all records of paymentvendor in those ids'.
Update:
If you want to print the contents of the object #pdf_vendor_details in raw form, you could use .inspect or .to_yaml.
For example, puts #pdf_vendor_details.inspect, will print the contents of the object.
Refer this question, to print contents of object.
#rest_ids=[21,22,23]
#pdf_vendor_details = PaymentVendor.where(id: #rest_ids )
puts "All details are, #{#pdf_vendor_details.inspect}"

Ruby rails - submit_tag / button_tag switch/toggle between names

How do I switch/toggle names between two or more names on single button?
For one condition I want the name to be as "Add", and for the other condition I want the name changed to "Remove". and switch between them based on status at the back end.
<%= button_tag "Add" , :id => "add_or_remove_button", :onclick => "javascript:add_or_remove_button()"%>
I can do "Add/Remove", and clicking on the same button will still do the job. But I want it specific.
Since you didn't say where the condition comes from, I will assume it is in an instance variable called #button_condition
You can do this (I haven't tested it)
button_tag(:type => 'button',:onclick => "javascript:add_or_remove_button()", :id => "add_or_remove_button") do
if #button_condition == X
"Add"
else
"Remove"
end
end
Take a look at: Button tag documentation

Rails 3 how to deal with constants

I have a constant called PAYMENT_METHODS in venue.rb.
PAYMENT_METHODS = ['Visa', 'MasterCard', 'American Express', 'Diners', 'JCB', 'Bankomat', 'sodexo', 'MA-Gutscheine']
You can check/uncheck the payment types in a form (payment_options is an integer):
<%= hidden_field_tag "venue[payment_options][]", nil %>
<% Venue::PAYMENT_METHODS.each do |category| %>
<%= check_box_tag "venue[payment_options][]", category %>
<%= label_tag category %>
<% end %>
Now I want to save the selection, but the value of each check box is the name of the payment option. I think I have to somehow add a key an store only the keys.
How do I set keys and save the collection to the database?
Thanks in advance
Make the constant a hash or an array, e.g.
PAYMENT_METHODS = {'Visa' => 1, 'MasterCard' => 2, 'American Express' => 3, 'Diners' => 4, 'JCB' => 5, 'Bankomat' => 6, 'sodexo' => 7, 'MA-Gutscheine' => 8 }
These will now be in a format that you can pass to options_for_select http://api.rubyonrails.org/classes/ActionView/Helpers/FormOptionsHelper.html#method-i-options_for_select.
If you (really) want checkboxes, an array is fine, just loop over using PAYMENT_MTHODS.each_index do |index| to get an iterator that's the value, and then use PAYMENT_METHODS[index].
I have always found it odd that the hash key is the part displayed in the list, but I guess it makes sense that the value is what is associated with the option's value :-).
Save the string value itself nothing wrong with that.
Its better to create a model like PaymentType and just keep id,name and in view render all payment types.This way you can better manipulate all available payment options in future from an admin panel (if needed) rather than going to a code level and changing at the constant.
You can use an element's index as a key. Use Array#index to your advantage.
PAYMENT_METHODS.index("Visa") #=> 0
PAYMENT_METHODS[0] #=> "Visa"
PAYMENT_METHODS.index("Diners") #=> 3
PAYMENT_METHODS[3] #=> "Diners"
A word of caution: This will break if you reorder PAYMENT_METHODS. You are keying an element to it's relative position in the array. Change the array and you change the keys. Avoid trouble by keeping your constants constant.
In regards to
I have always found it odd that the hash key is the part displayed in the list, but I guess it makes sense that the value is what is associated with the option's value :-).
you can get that done by (it was bugging me a bit as well)
<% Post::TECH_CATEGORY.each do |category| %>
<%= label_tag 'name', category[0] %>
<%= check_box_tag 'tech_cat', category[1] %>
<% end %>
It makes sense now that I can see it on the screen. Each object has two values, so...
category[0]
will always be the key you supplied for that specific object you are currently enumerating over
category[1]
will be the value of that same object. Looks way better on the screen.
which looks like in your example above
<label for="name"> Visa </label>
<input id="tech_cat" name="tech_cat" type="checkbox" value="1" />
Cheers,

Trying to populate gmaps4rails with multiple json strings in one page

I hope I am asking this right, so please let me know if I'm way off.
The problem is trying to build a homepage that draws from multiple controllers, to display the nearest locations from multiple controllers, ie. food, businesses, ect.
Right now the individual listings pages have maps drawn from their respective
#json = Controller.all.to_gmaps4rails
How would I do something like :
#json = Controller1 Controller2 .all.to_gmaps4rails
I hope this isnt a noob question and I'm just having a bad day. Thanks guys!
edit 12.5.2011 #seanhill - this is one of the models, the other sections are very close to this format. First off, I wasn't even sure if my homepage requires it's own model, as it doesn't interact with the db at all, more pulling data from controllers that do the work. Thanks for the response Sean!
class Dining < ActiveRecord::Base
validates_uniqueness_of :name, :message => "already exists"
attr_accessible :name, :address, :cuisine, :latitude, :longitude, :about, :facebook, :twitter, :phone, :website
geocoded_by :address
after_validation :geocode, :if => :address_changed?
acts_as_gmappable :process_geocoding => false
def gmaps4rails_address
"#{self.address}"
end
def gmaps4rails_infowindow
"<h3>#{self.name}</h3><br /><h5>#{self.cuisine}</h5>"
end
def self.search(search)
if search
where('name LIKE ?', "%#{search}%")
else
scoped
end
end
end
Try this
holder = Controller1.all
holder << Controller2.all
#json = holder.flatten.map{|h| {lng: h.longitude, lat: h.latitude, class: h.class.to_s}}.to_json
Make sure to change longitude and latitude based on your column names and use js to manipulate the markers based upon class.
As the #Sean Hill said you shouldn't be calling .all on controllers but I think you have a slight misunderstanding of how things are working. Assuming you have a Model called Dining and another called Shop, when you call Dining.all or Shop.all inside class DiningsController < ApplicationController, you are calling .all on either the Dining Model or the Shop Model not on the DiningsController.
The information you display through a controller is only limited by the methods you call in it although it is best practice ensure the main focus of the information displayed is related to the respective controller.
So what you are really trying to do is get the records from multiple models and group them together to display them in a single map.
With that said the answer should read something like this
holder = Dining.all # Takes all Dining records returned as an array and sets them to holder variable
holder << Shop.all # Pushes the Shop records array into the holder with the dining records
holder.flatten!# Next we flatten the array so we only have a single array.
# Then we use the map method to run the given code one time for each instance
# in the holder array to extract the info we need. The results for every instance
# in holder are returned in an array which we then convert to_json.
#json = holder.map{|h| {lng: h.longitude, lat: h.latitude, class: h.class.to_s}}.to_json
#json1 = something.to_gmaps4rails
#json2 = something.to_gmaps4rails
#json = (JSON.parse(#json1) + JSON.parse(#json2)).to_json
I populated the map with my initial data of festivals, and then added the rides to it with javascript with this code,
<% content_for :scripts do %>
<script type="text/javascript">
Gmaps.map.callback = function() {
$.getJSON('/rides_gmap', function(data){
Gmaps.map.addMarkers(data);
});
}
</script>
<%end%>
In the rides controller I had this
def rides_gmap
#rides = Ride.all
#json = #rides.to_gmaps4rails do |ride, marker|
marker.infowindow render_to_string(:partial => "/rides/infowindow", :locals => { :ride => ride})
marker.picture({
'picture' => view_context.image_path("orange-dot.png"),
'width' => 20,
'height' => 20
})
marker.title "#{ride.address}"
marker.json({:ride_id => ride.id, :ride_festivaltype => ride.festival.festivaltype
end
respond_with #json
end
I hope this helps.

Add readable field descriptions to ActiveRecord models

I'd like to add descriptions to ActiveRecord model fields to serve as basic instructions / examples for each of the fields. Basically model metadata. I can then display these in the UI (next to the fields on a form etc.)
The way I'm planning to do it is simply create a static hashtable inside the model with the field name as the key and description as the value. I.e.
FIELD_DESCRIPTIONS = {
'category' => 'Select the category it should appear within.',
'title' => 'The title should be a short but descriptive summary.',
'description' => 'Please enter a full description.'
}
etc.
Then I would create a a basic form helper that would wrap these explanations inside of a span (initially hidden and shown via jQuery) so they could be instatiated via f.field_description(:title) or something along those lines.
Anyone have any better ideas? I'd like to keep this field metadata in the model since many views could use the same information, and I also think it's nice to have descriptions within the model when you're going back to look at the code (like how DataMapper can be used right within the model to specify fields).
To give you a little more detail on what I've already done (and it works fine) here's the code. I think there has to be a prettier way of expressing these descriptions in the model, so let me know if you have any ideas.
In model:
FIELD_DESCRIPTIONS = {
'category' => 'Select the category it should appear within.',
'title' => 'The title should be a short but descriptive summary.',
'description' => 'Please enter a full description.'
}
def self.describe_field(field)
FIELD_DESCRIPTIONS[field]
end
In application_helper.rb
def field_helper(form, field)
"<span class='field_helper'>#{form.object.class.describe_field(field)}</span>"
end
In view:
<%= field_helper(f, 'title') %>
This will produce the desired output:
<span class='field_helper'>The title should be a short but descriptive summary.</span>
UPDATE:
Ok So this is the final code I'm using based on the accepted answer.
File: /config/initializers/describe_attr.rb
if defined?(ActiveRecord)
# let's us add attribute descriptions to each AR model
class ActiveRecord::Base
def self.describe_attr(*params)
attrs = params.shift
unless attrs.nil?
case attrs
when Hash
##attr_descriptions = attrs
when Symbol
return ##attr_descriptions[attrs]
end
end
##attr_descriptions ||= {}
end
end
end
File: /app/models/project.rb
describe_attr(
:category => 'Select the category the project should appear within.',
:title => 'The title should be a short but descriptive summary of the project.',
:description => 'Describe the project in detail.',
:image => 'Upload an image for the project.'
)
File: /app/helpers/application_helper.rb
# assumes you have a style defined for attr_description
def describe_attr(form, attribute)
"<span class='attr_description'>#{form.object.class.describe_attr(attribute)}</span>"
end
File: /app/views/projects/_form.html.erb
<%= describe_attr(f, :title) %>
The hash is a reasonable simple solution, but if you're on rails 2.2 or higher you might want to try the internationalization api to do this. This would also put you in a good place if you ever wanted to add translations.
Check out the i18n guide for details, but basically you would create a config/locales/en.yml that includes your column names like:
en:
labels:
category: Select the category it should appear within.
Then in your view:
<%= t('labels.category') %>
The namespace is your call of course. Also check out section 4.1.4 for a neat way to separate translations based on your current view template.
If you want to patch ActiveRecord, then you can do something like:
# Add this at the bottom of enviroment.rb
class ActiveRecord::Base
def self.field_description(*params)
attrs = params.shift
unless attrs.nil?
case attrs
when Hash
##field_description = attrs
when Symbol
return ##field_description[attrs]
end
end
##field_description ||= {}
end
end
And inside your model you can add this line like a macro:
class Product < ActiveRecord::Base
field_description :category => 'Select the category it should appear within.',:title => 'The title should be a short but descriptive summary.',:description => 'Please enter a full description.'
end
To get the value
Product.field_description : title
You can mix your solution with the label helper itself:
f.label :title, f.describe(:title)
And in your model:
FIELD_DESCRIPTIONS = {
:category => 'Select the category it should appear within.',
:title => 'The title should be a short but descriptive summary.',
:description => 'Please enter a full description.'
}
def describe(:field)
self.class::FIELD_DESCRIPTIONS[field]
end
Be sure to check out formtastic, which includes support for internationalized (or not) field labels as per matschaffer's answer.
http://github.com/justinfrench/formtastic/

Resources