Rails 3 how to deal with constants - ruby

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,

Related

Trying to break an array into three uneven arrays (Ruby on Rails)

Here's the code that will yield an array (I believe it's an array) of 13 page titles. I'd like to have titles 0-5 be in its own div, 6-8 in a second div and 9-12 in a third, for dropdown menus. I couldn't find this exact question/answer here.
<% #cms_site.pages.root.children.published.each. do |page| %>
<%= link_to page.label, page.full_path %>
<% end %>
Thank you!
What have you attempted? #each is not a very good use for this case. You might want to separate it into 3 different loops like so:
<% #cms_site.pages.root.children.published[0,5].each do |page| %>
<%= link_to page.label, page.full_path %>
<% end %>
<% #cms_site.pages.root.children.published[6,8].each do |page| %>
<%= link_to page.label, page.full_path %>
<% end %>
<% #cms_site.pages.root.children.published[9,12].each do |page| %>
<%= link_to page.label, page.full_path %>
<% end %>
EDIT
It seems like you're having some logic problems, it'd be wise for you to attempt it first at least.
The code up there should work but it's not really DRY and it can be extracted into maybe a helper method that uses the chapters for the iterator or possibly use a different iterator (e.g. each_with_index) and handle the check for each index in the block. There's many ways to go about doing what you asked.
Basically, if you're dealing with an array and you want to take the exact same elements from it each time, here's how to slice it:
# Your Array
elements = [1,2,3,4,5,6,7,8,9,10,11,12]
# This will give you three arrays inside one array. The first will be first six
# elements starting from 0, the second is 3 elements starting from 6, etc.
arrays = [ elements[0,6], elements[6,3], elements[9,3] ]
Now you can iterate through the array and reuse the code to generate the code you want.
arrays.each do |ar|
# Now render for each array as you please, and reuse the same code.
end

Redmine modification for issue number

I would like to hide the issue number on the issue list.
I use "Redmine 2.3.1" and the file to achieve that is this file: ./app/views/issues/_list.html.erb
It contains this line:
<%= raw query.inline_columns.map {|column| "<td class=\"#{column.css_classes}\">#{column_content(column, issue)}</td>"}.join%>
And the array query.inline_columns contains the id for example. I thought modifying this array would help me with my problem, but the changes aren't saved.
This is what I tried:
<%= #query.inline_columns.inspect %>
=> [#<QueryColumn:0x00000003607928 #name=:id ... and so on>]
<% #query.inline_columns.delete_at(0) %>
=>
<%= #query.inline_columns.inspect %>
=> [#<QueryColumn:0x00000003607928 #name=:id ... and so on>]
Why was the delete_at useless? And how would I modify this array or hide the number?
A few things to note:
#query.inline_columns might not an array. It may quack like an Array, but it's not.
#query.inline_columns.delete_at(0) should have returned something. Did it return and you ommited?
And last, but not least, the most probable guess I can make:
#query.inline_columns fetches something, converts it to an array and dups it before returning. The only way you can do something like that would be:
some_columns = #query.inline_columns
some_columns.delete_at(0)
some_columns
This is my solution now:
<% if #project.id == 1 %>
<% #qcols = query.inline_columns.reject{ |col| col.name.to_s == 'id' } %>
<% else %>
<% #qcols = query.inline_columns.each %>
<% end %>
So I took advantage of the reject method. And then I work with the #qcols.
Posted on behalf of OP.

How to generate pages for each tag in nanoc

I am new to nanoc and I am still finding my around it. I am able to get my site ready, it looks good and functions good, too. But I need to have a tags area. I am able to achieve that with
<%= tags_for(post, params = {:base_url => "http://example.com/tag/"}) %>
But how do I generate pages for tag? So for instance there is a tag called "NFL", so every time a user clicks on it, he/she should be directed to http://example.com/tag/nfl with a list of articles that correspond with NFL.
I can setup a layout which will do that. But then what kind of logic should be I using? And also do I need to have a helper for this?
You can use a preprocess block in your Rules file in order to generate new items dynamically. Here’s an example of a preprocess block where a single new item is added:
preprocess do
items << Nanoc::Item.new(
"some content here",
{ :attributes => 'here', :awesomeness => 5000 },
"/identifier/of/this/item")
end
If you want pages for each tag, you need to collect all tags first. I’m doing this with a set because I do not want duplicates:
require 'set'
tags = Set.new
items.each do |item|
item[:tags].each { |t| tags.add(t.downcase) }
end
Lastly, loop over all tags and generate items for them:
tags.each do |tag|
items << Nanoc::Item.new(
"",
{ :tag => tag },
"/tags/#{tag}/")
end
Now, you can create a specific compilation rule for /tags/*/, so that it is rendered using a "tags" layout, which will take the value of the :tag attribute, find all items with this tag and show them in a list. That layout will look somewhat like this:
<h1><%= #item[:tag] %></h1>
<ul>
<% items_with_tag(#item[:tag]).each do |i| %>
<li><%= link_to i[:title], i %></li>
<% end %>
</ul>
And that, in broad strokes, should be what you want!

Rails 3.0 - Where to put this logic?

I've got a Model Task with a member due_date. I'm using Chronic to take natural language input from the user and convert it to a Time, which then gets saved to the model.
I'm just not sure the best Rails, MVC-ish way to handle these use cases:
Display a formatted string (with some logic involved) to the user every time I show Task.due_date
Allow the user to input plaintext and have it parsed automagically everywhere they can edit Task.due_date
A helper method to format time was my first idea, like this:
<%= format_time task.due_date %>
combined with an overloaded setter on an accessor in my Task model, like this:
attr_accessor :due_date_string
def due_date_string=(string)
self.due_date = Chronic.parse(string)
end
This works everywhere I want it to except in my forms for editing:
<div class="field">
<%= f.label :due_date %>
<%= f.text_field :due_date_string %>
</div>
I don't know how to make the f.text_field element 'wire up' properly so that it saves to :due_date_string, but uses the helper method to display the string.
I don't necessarily need specific code examples, just looking for the kind of pattern that pro Rails-ers would use here.
Thanks!
With according to MVC conventions, data handle is about Model layer responsibility.
So you are going in right direction to do a setter (wrapper for due_date attribute):
You need to check that is attr_acessible that is access to get a data from params
def due_date_string=(string)
self.due_date = Chronic.parse(string) || Date.today
end
The representation logic to show the parsed date is Helper layer responsibility
In order to use:
f.text_field :due_date_string
Don't you also need a getter for the new attribute? e.g.,
def due_date_string
format_time self.due_date
end
Perhaps share what error or failure occurs when you use the custom text field. :)

Iterate Form fields

I have build a module to add translations for each standard topic. Theses topic got many standard options and you can translate it directly in page.
I got an issue with my form about the edit view.
When i display a translation it's repeat all value of the f.input :value each time he have one and i want it to display with the each of standard value.
The question is how i can iterate my input field :value in the form to display only once per standard value and not repeat all value translated by standard value.
when i want create a new one all workings fine. It's just about the iterate field who is repeated how many times he got a field in the table.
the gist for my code :
https://gist.github.com/266562670cd8dab28548
Change:
<%= #preference_topic.preference_topic_options.each_with_index do |option, index| %>
<%= f.fields_for option.preference_topic_option_translations.first, option do |translate_form| %>
to:
<%= #preference_topic.preference_topic_options.each_with_index do |option, index| %>
<%= f.fields_for option.preference_topic_option_translations.first || option.preference_topic_option_translations.build, option do |translate_form| %>

Resources