I'm trying to get Slim to generate the following HTML if a CONDITION is true:
<div id="start_button" hidden="hidden">
I have tried various methods, like the obvious:
#start_button #{('hidden="hidden"' if CONDITION?)}
= link_to 'Get Started', ...etc...
but that generates:
<div id="start_button">hidden="hidden"
= link_to 'Get Started',..etc...
I know how to do it when setting an attribute like class etc. to something, but because it has got to be all or nothing with "hidden", it's causing me issues.
I've been down quite a few rabbit holes this evening, so any help appreciated!
This is stated in the docs:
Ruby attributes
Write the ruby code directly after the =. If the code contains spaces
you have to wrap the code into parentheses (...). You can also
directly write hashes {...} and arrays [...].
So, anything that's inside () is evaluated as Ruby code, if the statement is evaluated to false, it's somehow "skipped", otherwise it does what's stated in the true branch.
#start_button hidden=('hidden' if true)
<div hidden="hidden" id="start_button"></div>
#start_button hidden=('hidden' if false)
<div id="start_button"></div>
Related
I'm returning to Rails after almost 5 years away and building out a personal project. In my _form.html.erb file, I'm trying to use a field, but the data never gets saved where I think it will be.
<select>
<%= options_for_select([['black'], ['blue'], ['red']], :selected => :color) %>
</select>
In my index, when I try to use model.color I get nothing returned. I'm sure its something basic I'm not getting, but for some reason Google searches and example code doesn't look like exactly like what I got. I'm not sure what option to pass to tell the form where to save the selected value.
You need to give the select tag a name (e.g. <select name="foo"> populates params[:foo], <select name="foo[bar]"> populates params[:foo][:bar]; alternatively use the select_tag/select form helper methods – see https://api.rubyonrails.org/classes/ActionView/Helpers/FormTagHelper.html#method-i-select_tag and https://api.rubyonrails.org/classes/ActionView/Helpers/FormBuilder.html#method-i-select).
Be aware: If you haven't used Rails for several years, chances are you don't know about strong parameters which you need to use if you want to do direct assignment (e.g. User.new(params[:user]) doesn't work as it used to in older Rails versions – you need to use strong parameters here). Details: https://edgeguides.rubyonrails.org/action_controller_overview.html#strong-parameters.
You need to assign the input a name in order to do anything meaningful with it - This is not Rails specific. Its universally true for web development. Form data in HTTP is just a bunch of key value pairs and the name attribute sets the key.
In Rails you should use the form builders and input helpers unless you have a very good reason not to - it is after driven by convention over configuration. They will handle assigning the name attribute for you:
<%= form_with(model: #thing) do |f| %>
<%= f.select :color, [['Black','black'], ['Blue','blue'], ['Red', 'red']] %>
# ...
<% end %>
This renders something like:
<select name="things[color]">
<option value="black">Black</option>
# ...
</select>
And would give you the following params hash:
{
thing: {
color: 'black'
}
}
They also provide data bindings between your model and the form so that the inputs are not reset when the user submits an invalid form.
I would really start by reading the rails guides as you have a lot to catch up on.
Sometimes it's more convenient to print in <%%>. How to do it in Rails?
http://api.rubyonrails.org/classes/ActionView/Helpers/TextHelper.html#method-i-concat
Should be what you are looking for.
E.g. the following statement using concat:
<% concat "Output" %>
is equivalent to:
<%= "Output" %>
In ERB:
The <% %> signify that there is Ruby code here to be interpreted.
The <%= %> says output the ruby code, ie display/print the result.
So it seems you need to use the extra = sign if you want to output in a standard ERB file.
Otherwise, you could look at alternatives to ERB which require less syntax,.. maybe try something like HAML. http://haml-lang.com/tutorial.html
Example:
# ERB
<strong><%= item.title %></strong>
# HAML
%strong= item.title
Is that more convenient?
erb has two method to evaluate inline ruby expressions. The <% which evaluates the expression and the <%= which evaluates and prints. There is no global object to print to within the binding context.
As mentioned by Omar, there is a concat method, which is part of ActionView. This will do what you want.
Unlike a scripting language escape, there is no default output for erb. Since erb is simply a function, and given a template and binding will return a variable, it returns the values of text and functions recursively.
There is hot debate as to how much logic should be allowed in a view, but as little as possible is what most people aim for. If you are putting more code than text in the view, you may want to consider refactoring your code.
UPDATE: Haml, indeed, already does this automatically! However, I had a hash inside of link_to helper, not a Haml tag and didn't even notice it. Silly me! So the question is pretty much invalid.
Haml makes rendering boolean HTML attributes very easy:
%input{checked: #boolean}
renders a simple <input> if #boolean is falsy, or <input checked> otherwise.
Haml also makes it easy to render data attributes:
%a{data: { is_special: false } }
renders: <a data-is-special="false">.
Is there any way to ask Haml to interpret this custom data-is-special attribute as a boolean one? I would like to not have it present if a falsy value is assigned, and for it to be present if anything truthy is assigned.
Code in brackets is normal ruby code, so if only you could perform this task in ruby, you have yourself a solution. I came up with something like that:
def remove_false(hsh)
Hash[hsh.each_pair.select {|key, value| value}]
end
{data: remove_false(is_special: false)} #=> {:data => {}}
This solution does not play well if you have combined keys that you want to treat specially and normally in single hash.
<li<% if #flits.first == flit %> class="first" <% end %>>
I created css for #flits_list and #flits_list :hover in application.css in Rails 3 but I would like the first flit in the list (flits_list.first) to have different css so I created a class, but this code returns the error
no method error in home#index. you have a nil object when you didn't expect it! You might have expected an instance of array. the error occurred while evaluating nil.first
Any help would be greatly appreciated.
The problem is that #flits is nil, presumably because your all_flits method is returning nil.
However, I'd recommend not putting that logic in the view, breaking up a tag like that. You have several options to make it cleaner:
Option 1: Use the CSS pseudo-class first-child like so:
li:first-child {
...
}
This has the advantage of not requiring any back-end logic or special markup. The only downside is that it has spotty older browser support, e.g. IE6.
Option 2: Use the Rails tag helpers.
<%= content_tag :li, :class => #flits.first==flit?"first":"" %>
Option 3: Tuck it away in a helper method
<%= li_for_flit %>
Then in the helper:
def li_for_flit
#spit out your tag here
end
Sometimes it's more convenient to print in <%%>. How to do it in Rails?
http://api.rubyonrails.org/classes/ActionView/Helpers/TextHelper.html#method-i-concat
Should be what you are looking for.
E.g. the following statement using concat:
<% concat "Output" %>
is equivalent to:
<%= "Output" %>
In ERB:
The <% %> signify that there is Ruby code here to be interpreted.
The <%= %> says output the ruby code, ie display/print the result.
So it seems you need to use the extra = sign if you want to output in a standard ERB file.
Otherwise, you could look at alternatives to ERB which require less syntax,.. maybe try something like HAML. http://haml-lang.com/tutorial.html
Example:
# ERB
<strong><%= item.title %></strong>
# HAML
%strong= item.title
Is that more convenient?
erb has two method to evaluate inline ruby expressions. The <% which evaluates the expression and the <%= which evaluates and prints. There is no global object to print to within the binding context.
As mentioned by Omar, there is a concat method, which is part of ActionView. This will do what you want.
Unlike a scripting language escape, there is no default output for erb. Since erb is simply a function, and given a template and binding will return a variable, it returns the values of text and functions recursively.
There is hot debate as to how much logic should be allowed in a view, but as little as possible is what most people aim for. If you are putting more code than text in the view, you may want to consider refactoring your code.