Refactoring into partials in Rails - ruby-on-rails

In page1, I use code A+B+C
In page2, I use code B+C
So when I make a partial, I realy have no idea in how to deal with this.
For example, In a Post-Comment system. I want to show #comments in 2 different pages. In the comment index page,
We show the post it belongs to. And in the post show page, We only have to show the comments content.(Since there is no need to show the comment.post again)
#Comment Index Page
<% #comments.each do |comment| %>
<%= comment.post %>
<%= comment.author %>
<%= comment.content %>
<% end %>
..
#Post Show Page
<% #comments.each do |comment| %>
<%= comment.author %>
<%= comment.content %>
<% end %>
So, how do I make a partial to reuse the code? Perhaps like this? But this there more elegant way of doing this?
#Comment Index Page
<% #comments.each do |comment| %>
<%= comment.post %>
<%= render comment %>
<% end %>
#Post Show Page
<% #comments.each do |comment| %>
<%= render comment %>
<% end %>
Updated:
I adopt the local variable approach, and update my code like:
# partial
<% if include_topic %>
<div class="Topic">
<h5><%= link_to "#{comment.topic.content}", comment.topic %></h5>
</div>
<% end %>
#Index
<%= render #comments, :locals => {:include_topic => true } %>
But I get undefined local variable or method `include_topic' for #<#
I just find nowhere to debug this issue

Your partial:
<%= comment.post if include_post %>
<%= comment.author %>
<%= comment.content %>
your code:
#index page
<%= render :partial => "partial_path", :collection => #comments, :as => :comment, :locals => {:include_post => true } %>
#show page
<%= render :partial => "partial_path", :collection => #comments, :as => :comment, :locals => {:include_post => false } %>
Syntax could be much shorter but it depends whether or not you stick to rails conventions see doc.
Sidenote: I don't like 1.8.7 syntax

In the partial,
<% comments.each do |comment| %>
<%= comment.post if params[:controller] == "comments" %>
<%= comment.author %>
<%= comment.content %>
<% end %>
and now render this partial in both comments/index and posts/show pages by specifying the comments as a local variable.

Related

Render form partial from view ROR

Im trying to render a form from another controller in my view.
This is posts_index, and the render post.comments works fine, but the form for a new comment doesnt.
<% #posts.each do |post| %>
<%= link_to post.title, post %>
<%= simple_format post.text %>
<%= render post.comments.order('created_at DESC').all %>
<%= render :partial => '/comments/form', locals: {post: post} %>
I get this error: undefined method `comments' for nil:NilClass
The comments form:
<%= form_for([#post, #post.comments.build]) do |f| %>
<%= f.label :Comment %><br />
<%= f.text_area :body, :class => "comment_text_box" %>
<%= f.submit %>
<% end %>
I understand I need to pass the post.comments to the form, but can't figure out how.
Post_show works with <%= render "comments/form" %>
Post and comments are a has_many relationship, posts has_many comments.
Thanks for looking.
You need to pass variables into your partial like this:
<% #posts.each do |post| %>
<%= link_to post.title, post %>
<%= simple_format post.text %>
<%= render post.comments.order('created_at DESC').all %>
<%= render partial: '/comments/form', locals: {post: post} %>
<% end %>
and change your form partial to this:
<%= form_for([post, post.comments.build]) do |f| %>
// form fields
<% end %>
When you ask for the partial, you need to send it the post it's related to. It would look like this:
<% #posts.each do |post| %>
<%= link_to post.title, post %>
<%= simple_format post.text %>
<%= render post.comments.order('created_at DESC').all %>
<%= render :partial => '/comments/form', post: post%>

Rendering a partial inside a block

I'm new to rails. I have this block in my view afrikaans.html.erb
<% #afrikaans.each do |course| %>
<div class="course">
<h3 class="course-name"><%= link_to course.name, course.url %></h3>
<% if I18n.locale == I18n.default_locale %>
<p class="course-description_en"><%= course.description_en %></p>
<% else %>
<p class="course-description_se"><%= course.description_se %></p>
<% end %>
<% if course.youtube_url.blank? == false %>
<p><%= raw ApplicationHelper.youtube_embed(course.youtube_url) %></p>
<% end %>
<% if course.language_id == 1 %>
<p> <%= image_tag("eng.png", :alt => "England", :class =>"round") %></p>
<% else %>
<p> <%= image_tag("swe.png", :alt => "Sweden", :class =>"round") %></p>
<% end %>
<% if ApplicationHelper.active_link?(course.url) == false %>
<td><%= I18n.t('home.broken_link') %></td>
<% end %>
<p><%= course.nbr_of_votes %> <%= I18n.t('home.votes') %></p>
</tr>
<% end %>
I also have another file swahili.html.erb with the same structure. I wanted to implement something like this
afrikaans.html.erb
<% #afrikaans.each do |course| %>
<%= render 'shared/partial' %>
<% end %>
So that I can also have
swahili.html.erb
<% #swahili.each do |course| %>
<%= render 'shared/partial' %>
<% end %>
The partial will contain the part of the block. I've tried this but it's not working. My question is this even possible in rails and if so what could be the problem. What options do I have if it isn't possible so that I can avoid the repetition since the two files have the same structure?
Update. This One worked out for me. I only needed to add :course => course on the block so that my views becomes something like
<% #afrikaans.each do |course| %>
<%= render 'shared/course_body', :course => course %>
<% end %>
Of course I've not named my partial "partial". This was just a matter of asking. Thanks to one #Alexander Panasyuk's answer.
Just create shared directory within your app/views path. And create file _partial.html.erb inside shared:
<div class="course">
<h3 class="course-name"><%= link_to course.name, course.url %></h3>
<% if I18n.locale == I18n.default_locale %>
<p class="course-description_en"><%= course.description_en %></p>
<% else %>
<p class="course-description_se"><%= course.description_se %></p>
<% end %>
<% if course.youtube_url.blank? == false %>
<p><%= raw ApplicationHelper.youtube_embed(course.youtube_url) %></p>
<% end %>
<% if course.language_id == 1 %>
<p> <%= image_tag("eng.png", :alt => "England", :class =>"round") %></p>
<% else %>
<p> <%= image_tag("swe.png", :alt => "Sweden", :class =>"round") %></p>
<% end %>
<% if ApplicationHelper.active_link?(course.url) == false %>
<td><%= I18n.t('home.broken_link') %></td>
<% end %>
<p><%= course.nbr_of_votes %> <%= I18n.t('home.votes') %></p>
</tr>
Then render your partial in afrikaans.html.erb like that:
<% #afrikaans.each do |course| %>
<%= render 'shared/partial', :course => course %>
<% end %>
or in swahili.html.erb:
<% #swahili.each do |course| %>
<%= render 'shared/partial', :course => course %>
<% end %>
It is most definitely possible, and usually a good idea.
In the future it would be nice if you could post the actual results and/or error messages you get, which would help a lot when trying to help you.
That said, I'm guessing you need to pass the course variable to your partial. Change
<%= render 'shared/partial' %>
to
<%= render 'shared/partial', :course => course %>
Partials do not have access to local variables in other partials. In that sense you can think of each partial as separate methods on the same object instance.
<%= render 'shared/partial', locale: 'swahili', course: course %>
You will have local vars 'locale' and 'course' in your partial set to 'swahili' and #course, respectively. Also, I'd advise to name your partials something more meaningful, like 'course'.

Check for nil?, Blank?

I have a model and for some reason I am trying to tell rails if there is nothing created then render add a new show link.
<% if #show != blank? %>
<%= link_to 'Add a new show', new_show_path %></br>
<% else %>
<%= render(:partial => 'shows/show', :locals => {:show => #profile.shows.last}) %>
<% end %>
It adds the Add a new show link but once a show is created I still only see the link and not the partial. If I create the show and put the render at top like so then I can see it but if i delete the show it returns an error.
I've tried these also
<% if #show.present? %>
<%= render(:partial => 'shows/show', :locals => {:show => #profile.shows.last}) %>
<% else %>
<%= link_to 'Add a new show', new_show_path %></br>
<% end %>
<% if #show.blank? %>
<%= link_to 'Add a new show', new_show_path %></br>
<% else %>
<%= render(:partial => 'shows/show', :locals => {:show => #profile.shows.last}) %>
<% end %>
<% if #{model} nil? %>
<%= link_to 'Add a new show', new_show_path %></br>
<% else %>
<%= render(:partial => 'shows/show', :locals => {:show => #profile.shows.last}) %>
<% end %>
and it seems to never give me what I am looking for on both ends. It ethiers shows me the link and nevers shows the partial once created or it shows the partial but when I delete it it gives me an error.
How can I tell rails that if there is no shows created to render the add new link and once there is a show created to render the partial?
Are you actually filtering this by profile? It looks like you're rendering a page for the last show of a profile. (#profile.shows.last)
<% show = #profile.shows.last %>
<% if show.blank? %>
<%= link_to 'Add a new show', new_show_path %>
<br />
<% else %>
<%= render 'shows/show', :show => show %>
<% end %>
Use the .blank? method for the global variable you're trying to tell if it's empty. If its an array or hash. Use .nil? If its supposed to be anything else.

current action name problem

When i am in /edit action, i see edit button but the problem is if there is an error in form validation it renders action edit and i see create button. how can i fix it?
<%= form_for(#page) do |f| %>
<% if controller.action_name =="edit" %>
<%= f.submit "Update" %>
<% else %>
<%= f.submit "Create" %>
<% end %>
<% if ["edit", "update"].include? params[:action] %>
<%= f.submit "Update" %>
<% else %>
<%= f.submit "Create" %>
<% end %>
Better solution is to extract your form as a partial and send local variable with button name to it
your edit view:
<%= render :partial => "form", :locals => { :button_label => "Edit" } %>
your create view:
<%= render :partial => "form", :locals => { :button_label => "create" } %>
your _form partial:
<%= form_for #object ... do |f| %>
...
<%= f.submit button_label %>
<% end %>
UPD
I think #idlefingers solution the best for your issue
You could just use f.submit with no arguments. This will create names like "Update Page" and "Create Page". If you want to change the wording of these, they can be set in your locale. No conditionals, no messing about with action names. Simple.
Try to do this check:
<%= form_for(#page) do |f| %>
<% if controller.action_name =~ /update|edit/ %>
<%= f.submit "Update" %>
<% else %>
<%= f.submit "Create" %>
<% end %>
My solution:
<%= form_for(#page) do |f| %>
<%= f.submit(f.object.new_record? ? "Create" : "Update") -%>
<% end %>

Ajax Question - Ruby on Rails - Error: Couldn't Find Post without an ID

Ok, I am new to rails so I hope I explain this well. I seem to have a problem with a form collecting the proper information. Work in one spot and not another. Here is the situation.
I have created a blog with three tables, posts, comments, and votes. I have comments working correctly and votes working partially. Here is what I mean.
The /posts/show.html.erb file basically shows the post, the associated comments and it shows how many votes that post has. I am working the votes but using a form with a hidden field that delivers a value of '1' along with the post_id to the table. I am then using AJAX to return the #post.votes.count. This all works great.
I am trying to use this same vote/return mentioned above but on the /posts/index.html.erb page. In the index page I have the <% #post.each do |post| %> doing two things. First render :partial => post %> and then I have the same code that I am using on the show.html.erb page. The error that I am getting from the terminal is
ActiveRecord::RecordNotFound (Couldn't find Post without an ID):
app/controllers/votes_controller.rb:4:in `create'
I am guessing this has to do with it being part of the index record set which doesn't have a unique post param associated with the page. I am hoping there is a simple fix. Here is the code:
This is the /posts/show.html.erb code that is working correctly:
<div id="backto"<%= link_to 'Back to all BattleCries', posts_path %>
</div>
<%= render :partial => #post %>
<div id="beltcomments">
<div id="beltcommenttext">
<div id="vote">
<div id="votes">
<%= #post.votes.count %> People liked this BattleCry.
</div>
</div>
<div id="votebutton">
<% remote_form_for [#post, Vote.new] do |f| %>
<%= f.hidden_field :vote, :value => '1' %>
<%= f.submit "Like" %>
<% end %>
</div>
</div>
</div>
<div id="beltcommentsbottom">
</div><br/><br/>
<div id="belt">
<div id="belttext">
<p5>Add a Comment</p5>
<% remote_form_for [#post, Comment.new] do |f| %>
<p>
<%= f.text_area ( :body, :class => "commentarea") %>
</p>
<%= f.submit "Add Comment"%>
<% end %>
</div>
<div id="beltbottom">
</div>
</div><br/>
<div id="comments">
<%= render :partial => #post.comments %>
</div>
<br/>
<div id="commenttime">
Copyright 2009, My Life BattleCry, LLC.
</div>
<br/>
<br/>
<br/>
Here is where it is in the index page:
<% #posts.each do |post| %>
<%= render :partial => post %>
<%= render :partial => #post %>
<div id="beltcomments">
<div id="beltcommenttext">
<div id="vote">
<div id="votes">
<%= post.votes.count %> People liked this BattleCry.
</div>
<%= link_to "Comments (#{post.comments.count})", post %>
</div>
<div id="votebutton">
<% remote_form_for [#post, Vote.new] do |f| %>
<%= f.hidden_field :vote, :value => '1' %>
<%= f.submit "Like" %>
<% end %>
</div>
</div>
</div>
<br/>
<br/>
<br/>
<% end %>
<div id="commenttime">
Copyright 2009, My Life BattleCry, LLC.
</div>
<br/>
<br/>
<br/>
Here is the votes_controller.rb
class VotesController < ApplicationController
def create
#post = Post.find(params[:post_id])
#vote = #post.votes.create!(params[:vote])
respond_to do |format|
format.html { redirect_to #post}
format.js
end
end
end
Here is the /votes/create.js
page.replace_html :votes, :partial => #vote
page[#vote].visual_effect :highlight
Lastly, here is the partial, /_vote.html.erb:
page.replace_html :votes, :partial => #vote
page[#vote].visual_effect :highlight
I hope this makes sense. Let me know if I need to clarify anything.
I imagine this is causing problems. You didn't post your posts controller, but does the index action set #post?:
<%= render :partial => #post %>
Looks like I just needed to change the following in the <% #posts.each do |post| %> section of the index.html.erb file.
<% remote_form_for [#post, Vote.new] do |f| %>
<%= f.hidden_field :vote, :value => '1' %>
<%= f.submit "Like" %>
to
<% remote_form_for [post, Vote.new] do |f| %>
<%= f.hidden_field :vote, :value => '1' %>
<%= f.submit "Like" %>

Resources