hash enumeration and using outside arguments - ruby

I have a form builder and the normal |f| variable. In the middle I'd like to iterate over some hash and get a list of keys by which to build the form. How can I incorporate "f" as an argument to the enumerator.
<%= form_for ..... do |f| %>
<% available_types.each do |k,v| %>
<%= f.text_filed :selection, :value => v %>
<% end %>
<% end %>
As you can see in the code above, "f" is outside of the scope. Ideas?

f should still be in the scope. You misspelled text_field though.

Related

simple_form - can't generate combined select input

I have complex form with a lot of controls, and I'm currently using simple_form gem due to its flexibility. But when I wanted to do something more complex I faced to several problems that currently looking obscure for me. I would like to introduce combined collection input, that will render both optgroups and single non-groupped selects. Generated html that I want to achieve should look something like this:
<select name="select" multiple="multiple">
<option value="1">Milk</option>
<optgroup label="Soda">
<option value="2">Cola</option>
<option value="3">Fanta</option>
</optgroup>
</select>
I've tried to create custom input class, but stucked on implementation details of input method, I simply couldn't find out how to generate proper output.
UPDATE
Currently quick and dirty implementation for custom input looks something like this, but I don't think that it is a good idea to drop all goodnesses with options that simple_form gives me.
class CombinedMultiselectInput < SimpleForm::Inputs::CollectionSelectInput
include ActionView::Helpers::FormTagHelper
include ActionView::Helpers::FormOptionsHelper
def input
out = ActiveSupport::SafeBuffer.new
option_tags = ungrouped_options.safe_concat(grouped_options)
out << select_tag(options[:name], option_tags, class: ['select', 'form-control'])
out
end
private
def ungrouped_options
# this can be retrieved from general collection like collection[:ungrouped]
collection = [["Foo", 2], ["Bar", 3]]
options_for_select(collection)
end
def grouped_options
# and this using collection[:grouped]
collection = [["Group", [["Foobar", 4]]]]
grouped_options_for_select(collection)
end
end
Using your current design you can combine the options_for_select and option_groups_from_collection_for_select methods like so.
def ungrouped_options
[["Foo", 2], ["Bar", 3]]
end
def grouped_options
[["Group", [["Foobar", 4]]]]
end
def your_hash
{"ungrouped" => ungrouped_options, "grouped" => grouped_options}
end
Then in your view something like this should work:
<%= content_tag(:select,nil,{multiple: true,name: "select"}) do
<%= your_hash.each do |k,v| %>
<% if k == "ungrouped" %>
<%= options_for_select(v) %>
<% else %>
#this works because:
# last will be the collection of children for a member
# first will be the group name
# last on the child will be the value method
# first on the child will be the text displayed
<%= option_groups_from_collection_for_select(v, :last, :first, :last, :first) %>
<% end %>
<% end %>
<% end %>
This will create the following:
<select name=\"select\" multiple=\"true\">
<option value=\"2\">Foo</option>
<option value=\"3\">Bar</option>
<optgroup label=\"Group\">
<option value=\"4\">Foobar</option>
</optgroup>
</select>
Obviously this was simplified to show how this could be done but hopefully this points you in the right direction.
You should also be able to wrap this for simple_form although I have not tested it.
<%= f.input :some_attribute do %>
<%= f.select :some_attribute do %>
<%= your_hash.each do |k,v| %>
<% if k == "ungrouped" %>
<%= options_for_select(v) %>
<% else %>
<%= option_groups_from_collection_for_select(v, :last, :first, :last, :first) %>
<% end %>
<% end %>
<% end %>
<% end %>

erb idiom to handle undefined variable

I'm trying to write some puppet .erb, I'd like to handle this "environment" variable if it's:
undefined
a string with newlines
an array.
I've got as far as this:
<% Array(environment).join("\n").split(%r{\n}).each do |f| %>
one line: <%= f %>
<% end %>
But haven't gotten around the undefined case yet. I've tried this
<% if (defined?(environment)).nil? %?
<% Array(environment).join("\n").split(%r{\n}).each do |f| %>
one line: <%= f %>
<% end %>
<% end %>
but am still getting "(erb):11: undefined local variable or method `environment' for main:Object (NameError)" when trying to test it like this:
ruby -rerb -e "environmentUNDEFINEME= [ 'cronvar=cronval', 'var2=val2' ];
puts ERB.new(File.read('templates/job.erb')).result"
Sorry this is so basic, but somebody's got to ask the easy questions. Any help?
I would do this:
<% if defined?(environment) %>
<% Array(environment).each do |f| %>
one line: <%= f %>
<% end %>
<% end %>
I didn't understand why you joining on new lines and then splitting on them again, so I removed it from the example.

Can I concatenate the result of two helper methods in single erb output

I created a helper to output some text using erb
<%= helper_method %>
but if i tried to put it 2 times it will not work ..for eg..
<% =
helper_method
helper_method
%>
I am expecting the text twice...but I get only once...
Each <%= %> outputs a single string, so either join them in a single string, or do it twice.
<%= helper_method %> (or <%= ... -%> )
<%= helper_method %>
There are a variety of ways to concatenate; %Q, normal string interpolation, etc.
try something like
<%= %Q(#{helper_method} #{helper_method}) %>
<%= helper_method + helper_method %>
If you need to print a String multiple times(the string in your case comes from a helper), you can simply use the multiplier operator
#helper
def helper_method
"Text"
end
#view
<%= helper_method * 2 %>
The result in a new string like this: TextText
HTH
When you say <%= helper_method %>, = means print the output, but when you say
<% =
helper_method1
helper_method2
%>
Rails doesn't know which out put should print, because it has two methods:
helper_method1
helper_method2

How to create a sequence of numbers in a Ruby on Rails form

I have 10 form fields and I want to append a number next to each field, going sequentially from 1 to 10. The problem is that the code is already in a loop. It's inside a partial, and the partial is passed a collection.
<%= fields_for "list", f do |f| %>
<!-- I want 1, 2, etc to appear here depending on the iteration. -->
<%= f.label :name %>
I tried using <%= i += 1 %> but it does not work since i is not defined. If I define i, it will keep getting reset to the same number, so it makes no difference. Any ideas?
Rails automatically defines a local variable called partialname_counter where, obviously, "partialname" is the name of your partial. So if your partial is called e.g. _list_item.html.erb you could write it like this:
<%= fields_for "list", f do |f| %>
<%= list_item_counter + 1 %>
<%= f.label :name %>
<% end %>
(The + 1, of course, is there because the counter starts at 0.)
Another option would be to just let the browser do the numbering for you using an ordered list:
In the view:
<ol>
<%= render :list_item, :collection => #some_items %>
</ol>
...and in the partial:
<%= fields_for "list", f do |f| %>
<li>
<%= f.label :name %>
</li>
<% end %>
This option is probably more semantic, and lists are easy to style in CSS.

reflection of erb variables

I'm using a puppet template, which does an erb interpretation of the template file. I'd like to know all the variables available to me, however, there are variables available (e.g., fqdn) that are not listed by any of the reflection methods I'm aware of, specifically, none of these:
<% Module.constants.each do |v| %># module constant: <%= v %>
<% end %>
<% Kernel.local_variables.each do |v| %># local variable: <%= v %>
<% end %>
<% Kernel.instance_variables.each do |v| %># instance variable: <%= v %>
<% end %>
<% Module.class_variables.each do |v| %># class variable: <%= v %>
<% end %>
<% Kernel.global_variables.each do |v| %># global variable: <%= v %>
<% end %>
Is there an extra reflection method for erb that will reveal these to me?
The "See all client variables" should do what you want
Don't really know about puppet templates, but if fqdn is a local variable, then calling local_variables (as in self.local_variables) should display it.
I don't know as much as I'd like to about erb's built-in means of reflection, but with Puppet, I think the hash returned by scope.to_hash is probably what you want. From the templating reference:
<% scope.to_hash.keys.each do |k| -%>
<%= k %>
<% end -%>
Alternately, if you just want a one-time look at the variables the agent node supplies, you can run facter on the node; that's how Puppet gets all that info in the first place.

Resources