How to reduce number of hierarchical 'if statements' - ruby-on-rails

I have hierarchical the statements like this
<% #descriptions.each_with_index do |description, i| %>
<% description.tale2.each do |tax_ref| %>
<% if condition %>
<% if condition %>
<% if condition %>
<%= $text_first_describe%> <%= $paren_author_yr %>
<% ref_sp_uniq.each_with_index do |ref, i| %>
<% if ref == tax_ref.ref_wo_brace%>
<% execution %>
<% elsif i == (ref_sp_uniq.size - 1)%>
<%# #ref_desc = "#{#ref_desc_numb}. #{tax_ref.ref_wo_brace}" %>
<% end %>
<% end %>
<% if condition %>
<% execution %>
<% elsif condition %>
<% execution %>
<% elsif taxon_name.emend_author_year %>
<%= print %>
<% else %>
<%= print %>
<% end %>
<% end %>
<% else %>
<% if condition %>
<%= print %>
<% ref_sp_uniq.each_with_index do |ref, i| %>
<% if condition %>
<% execution %>
<% elsif condition %>
<% execution %>
<% end %>
<% end %>
<% if condition %>
<% execution %>
<% elsif condition %>
<% execution %>
<% elsif condition %>
<% execution %>
<% else %>
<% execution %>
<% end %>
<% end %>
<% end %>
<% end %>
<% end %>
<% end %>
Kindly suggest me possible way to reduce this kind of junk "if statements".

If your nested IFs are becoming very complex, you might consider describing the entire structure with a state machine and processing it like that. That way you get the documentation of the formal state diagram and your code will be much simpler.
Edit:
Here is a better attempt to describe the process. The nice thing about
this is that once you have your initial state diagram and the code to
process it, adding new states is very easy to do. (Expecially if you
build a little tool to read your diagram and generate your table for
you).
Most people just use these in the context of regular expressions and
leave them alone otherwise, but it is a nice powerful tool to have in
your toolbox. A common example is implementing a full ftp server this
way is trivially easy.
Ok, to my better example, hope this helps.
Consider this IF psuedo code:
if (a < 5)
do_b
do_c
if (a < 3)
do_d
else
do_e
end-if
end-if
The state transition table to process this might look like:
State Transition Action Next state
----- ---------- ------ -----
1 a < 5 2
1 7
2 do_b 3
3 do_c 4
4 a < 3 5
4 6
5 do_d 7
6 do_e 7
7 exit
The code to process it would look like this:
currentState = 1
foreach table entry
if table_state == currentState
&& table_transition is true or blank
call table_action
currentState = table_next_state
Take a look at http://en.wikipedia.org/wiki/State_transition_table for a
more formal description.

first of all I would put this code in a helper, so you get rid of all the tags and you clean the view, then look if you can apply the case statement and latter remember maybe you can include line_of_code if condition or condition ? code_a : code_b.
Hard to do something without conditions (I suppose the condition change each if), why not to address the question to https://codereview.stackexchange.com/
?

Ruby's case syntax would probably be a good starting point for cleaning that up, but like others have mentioned you probably need to rethink whats going on in there. Ultimately you probably want to be moving as much of that logic into the model as you can.
My two cents.

Related

get first 3 occurrence of an array

In my rails app I have below code to print some data from database.
<% #di.each do |d| %>
<% if d["visibility_team"] == 'for_all' %>
//my code goes here
<% end %>
<% end %>
I just want to print first 3 occurrence which fulfill the d["visibility_team"] == 'for_all' condition.
How can I do this?
If you can't get #di as 3 records from DB, how about keeping counter how many ds were printed?
Something like this (feel free to style it the way you want)
<% counter = 0 %>
<% #di.each do |d| %>
<% if d["visibility_team"] == 'for_all' %>
<% counter += 1 %>
<% break if counter == 3 %>
//your code goes here
<% end %>
<% end %>
However it's usually a bad taste to have so much logic in views.

Conditionals and overriding

I'm using a conditional to check if two values exists. I want to override the first conditional with the second one. Most likely if the second one exists then the first will, if that makes sense. Not the issue i'm having is using two different call methods.
What I have so far:
<% #data.each do |i| %>
<% if i.stock.present? %>
In Stock
<% elsif i.sold.present? %>
Sold
<% else %>
n/a
<% end %>
<% end %>
So, if in stock display 'In Stock', if sold display 'Sold'.
I think I have a solution, but feel free to let me know if there is a better way. This is using the unless statement and seems to display what I need.
<% #data.each do |i| %>
<% unless i.stock.present? %>
In Stock
<% else if i.sold.present? %>
Sold
<% else %>
n/a
<% end %>
<% end %>
<% end %>

Rails how to make conditional inside iteration?

i'm trying to use a conditional inside a iteration but did not worked so, here the scenario:
in this case if the if the order or the product is present should just show the order and products with the feedback.
but even if is present show the feedback with odata and pdata.
someone know why?
<% #feedbacks.each do |feedback| %>
<% if order.present? && product.present? %>
<% order = feedback.order %>
<% product = order.product %>
<% else %>
<% odata = feedback.odata %>
<% pdata = odata.pdata %>
<% end %>
I guess this is what you are trying to do,
<% #feedbacks.each do |feedback| %>
<% if (order = feedback.order).present? && (product = feedback.product).present? %>
<%= order.title %>
<%= product.title %>
<% else %>
<%= (odata = feedback.odata).name %>
<%= odata.pdata.name %>
<% end %>
<% end %>
Note: title and name are assumed columns, replace it with your required/respected attribute.
Please go through this to understand the difference between various erb tags.
Comparison:
for the if condition you are trying to call order and product directly, which will throw error as they are related to feedback.
<% %> just executes the ruby code, you wanted to print the data so need to use <%= %>.
no need to save them in variable when you are not going to use it. I have saved them while checking the existence of the object in the condition and could use to display without querying the db.

Conditional <div> tags inside the view. Why bad?

In my rails app I have a very dynamic user dashboard that shows and hides div elements based on the users role (customer, employee, admin).
For example: users/show.html.erb
<% if current_user.role_id == 4 %>
<th>Edit</th>
<th>Delete</th>
<% elsif current_user.role_id == 1 %>
<th>Cancel Appointment</th>
<% else %>
<% end %>
</tr>
</thead>
I stored the table nav tabs inside their own partials like this:
<% if current_user.role_id == 1 %>
<%= render 'users/customer_bar' %>
<% elsif current_user.role_id == 2 %>
<%= render 'users/employee_bar' %>
<% elsif current_user.role_id == 4 %>
<%= render 'users/honcho_bar' %>
The same could be done for the aforementioned tags but that would not at all be DRY. Is there a better way? Why is it bad to conditionally format tags in this way?
Statement
Maybe you're looking for case / switch:
case current_user.role_id
when 4
#do something for 4
when 1
#do something for 1
end
--
System
I would highly recommend using a partial to get this to work:
<%= render partial: "your_partial", local: { your_local_var: "value" } %>
This will allow you to define the conditions in the partial itself:
#app/views/controller/your_partial.html.erb
<% if var == "value" %>
...
<% else %>
...
<% end %>
Bad?
I wouldn't say it's "bad" for the sake of it - it's typically the case that you'll need conditions. The issue, I think, is you need to ensure you're able to handle the conditions in the most effective way.
Using case / switch would be a legitimate way of doing this, however, you may have an issue further up the stack

Rails - Display inline rails errors

How can I condense my code into a single statement:
<% #policyholderdetail.errors.each do |attr,msg| %>
<% if attr == :title %>
<li><%=attr %> <%= msg %></li>
<% end %>
<% end %>
I would like to show only the errors for :title next to the field but feel there should be a better statement to do this as opposed to looping through all of the errors until I get to the one I want.
Question - can I condense the first two lines into one better statement?
You can write: #policyholderdetail.errors[:title]. See here.
Use
<% if #policyholderdetail.errors[:title].present? %>

Resources