Rails 3: Injecting partials through conditionals - ruby-on-rails

I'm looking to inject a partial/offset of a views pattern based on conditional statements. Don't know how to do this or how complex it may be. To better explain, here's some pseudo examples:
Totals: 1 Post & 3 Jobs
Pattern: 1 Job - 1 Post - 1 Job - 1 Job
A post is inserted between 3 jobs because there is more than 2. How would I do this?

I guess you could do something like this in your view file.
<% if #jobs.count > 2 %>
<% render_post = true %>
<% else %>
<% render_post = false %>
<% end %>
<% #jobs.each do |job| %>
<%= job.some_attribute %>
<% if render_post == true %>
<%= render #post %>
<% render_post = false %>
<% end %>
<% end %>
When render_post is true, rails renders post. When it is false, rails doesn't render post. However, render_post value doesn't appear in the html file.
You need _post.html.erb in the Post's view file.

Related

Rails keeps ignoring an IF statement inside the view

I am writing an application where I want to list blog posts according to date they were created on the main index page. So lets say if I have 10 blog posts that were created today I would want to have smth like this come on the index page of the app..
Today:
POST 1
POST 2
POST 3
... so on
However, I have this...
Today:
POST 1
Today:
POST 2
Today:
POST 3
... so on
The following is my code..
index.html.erb
<% #posts.reverse.each do |post| %>
<% flag = true %>
<% if post.date.day < Time.now.day &&
post.date.day >= (Time.now.day - 1.day) %>
<!-- This IF statement gets ignored -->
<% if flag == true %>
<%= "Today" %>
<% flag = false %>
<br />
<% end %>
<tr>
<td><p>IMAGINE THIS SENTENCE IS ONE POST</p></td>
</tr>
<% end %>
<% end %>
The if statement that gets ignored inside the code acts as a flag, so that it should execute only once per group of posts with the same date. But, Rails seems to completely ignore it for some reason. If someone could help me correct this issue or nudge me in the right direction, your help would be greatly appreciated.
It's not that the if is being ignored, but that on each post the flag is being set to true again.
The first time you set the flag has to be outside of the iteration, like this:
<% flag = true %>
<% #posts.reverse.each do |post| %>
<% if post.date.day < Time.now.day &&
post.date.day >= (Time.now.day - 1.day) %>
<% if flag == true %>
<%= "Today" %>
<% flag = false %>
<br />
<% end %>
<tr>
<td><p>IMAGINE THIS SENTENCE IS ONE POST</p></td>
</tr>
<% end %>
<% end %>

in_groups_of(3) but only for the first 3 groups

Expanding on New row every 3 items -- I'm trying to insert ads in between my Forem (https://github.com/radar/forem) topics -- one in between every 3 topics for the first 3 groups of topics (3 ads in total).
UPDATE
I ended up with this thanks to the answer below, unfortunately it doesn't seem to pass on test as a valid local (can't find topic inside forem/topics/topic):
<% #topics.in_groups_of(3).each_with_index do |grouped_topics, index| %>
<%= render partial: "forem/topics/topic", collection: grouped_topics %>
<% if index < 3 %>
<p>Ad</p>
<% end %>
<% end %>
Live test app (click the big green Run button to test):
http://runnable.com/VFUNK2ho3Fpr8Fp2/forem-with-ads-in-between-topics
File in question: views/forem/forums/show.html.erb
in_groups_of split your array into array of arrays, so that should be:
<% #comments.in_groups_of(3, false).each_with_index do |grouped_comments, index| %>
<% grouped_comments.each do |comment %>
...
<% end %>
<% if index < 3 %>
<%= image_tag "selfie.jpg">
<% end %>
<% end %>

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 4/ERB if/else loop gives unexpected ;, expected : error, if I add html or text

I'm trying to create a mobile app in Rails 4/ERB where people can post and comment on others' posts. I'd like to be able to toggle the visibility of comments using jQuery, but whenever I attempt to wrap the each loop in a div tag, or add comments count, I get an error. ('comments/comment' is a partial containing the template for the actual comment)
This works, but shows all the comments (not what I want):
<% if post.comments.count > 0? %>
<% post.comments.order(:created_at).reverse.each do |comment| %>
<%= render 'comments/comment', comment: comment %>
<% end %>
<%:%>
No comments yet.
<% end %>
this gives me an unexpected semicolon error:
<% if post.comments.count > 0? %>
<%= post.comments.count %> Comments.
<% post.comments.order(:created_at).reverse.each do |comment| %>
<%= render 'comments/comment', comment: comment %>
<% end %>
<%:%>
No comments yet.
<% end %>
so does this:
<% if post.comments.count > 0? %>
<div>
<% post.comments.order(:created_at).reverse.each do |comment| %>
<%= render 'comments/comment', comment: comment %>
<% end %>
</div>
<%:%>
No comments yet.
<% end %>
the exact words of the error are syntax error, unexpected ;, expected :
What am I doing wrong, and how can I use HTML within this block without it throwing an error at me? Any help would be much appreciated.
addendum: oddly enough, if I stick the comment count code inside the each loop, it works (but, because it's an each loop, displays it multiple times)
addendum 2: even this gives an error:
<%= render 'comments/form',post: post%></p>
<% if post.comments.count > 0? %>
<!--<%= post.comments.count %> Comments. -->
<% post.comments.order(:created_at).reverse.each do |comment| %>
<%= render 'comments/comment', comment: comment %>
<% end %>
<%:%>
No comments yet.
<% end %>
Try like this
<%= render 'comments/form',post: post%></p>
<% if post.comments.count > 0 %>
<!--<%= post.comments.count %> Comments. -->
<% post.comments.order(:created_at).reverse.each do |comment| %>
<%= render 'comments/comment', comment: comment %>
<% end %>
<%else%>
<!-- No comments yet. --->
<% end %>
remove ? in 2nd line because post.comments.count > 0 this will return true or false,so need to check again.
so,now you can use else condition.
As others have alluded to, the snippet if post.comments.count > 0? implies that you want to use the ruby ternary ?: operator. As its name implies, the ternary ?: operator is composed of 3 parts:
the condition
value if the condition is true
value if the condition is false
Here's an example of its use:
is_even = (num % 2) ? true : false
Note that in this example both the if check (?) and else (:) are included, as is required by the ternary operator. So the issue with your use of ? is that you're using the if check, but not the else check.

How to reduce number of hierarchical 'if statements'

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.

Resources