Render form partial from view ROR - ruby-on-rails

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%>

Related

Infinite scroll with group_by items

I'm trying to implement infinite scroll on a list of items (aka "Games" in my code) following this tutorial --> http://railsforbeginners.com/chapters/chapter-9-infinite-scroll/
Here is my view :
<% #game_days.each do |day, games| %>
<% for game in games %>
<%= game.game_external_link %>
<%= image_tag game.photos[0].image.url(:thumb), class:"img-responsive" if game.photos.length > 0 %>
<%= game.game_name %>
<%= game.game_description %>
<%= image_tag avatar_url(game.user) %>
<% end %>
<% end %>
I've tried to refacto the code putting the code between <%= game.game_external_link %> to <%= image_tag avatar_url(game.user) %> in a partial and then putting this <%= render #games %>. But i get an infinite loop now :(
So I need help to refacto and using partial (as it says in the article).
Cheers!
# app/vies/games/_game.html.erb
<%= game.game_external_link %>
<%= image_tag game.photos[0].image.url(:thumb), class:"img-responsive" if game.photos.length > 0 %>
<%= game.game_name %>
<%= game.game_description %>
<%= image_tag avatar_url(game.user) %>
You can then render the whole collection with just:
<%= render games %>
This is shorthand for:
<%= render partial: 'game', collection: games %>
See the rails guides for how this works.

Partial path error because of nil

I am working on a project and I just introduced polymorphism for posting text Posts and photo Posts.
When I try to post an image I get this error: "'nil' is not an ActiveModel-compatible object that returns a valid partial path."
The first show file (app/views/dashboards/show.html.erb) with code:
<%= form_for #text_post do |form| %>
<%= form.text_field :body, placeholder: 'Post content here' %>
<%= form.submit 'Post Title!' %>
<%end%>
<%= form_for #photo_post do |form| %>
<%= form.file_field :image %>
<%= form.submit 'Post Image!' %>
<%end%>
<%= render #posts %>
which leads to this at app/views/photo_posts/_photo_post.html.erb with the following code:
<%= image_tag photo_post.image.url(:post) %>
The app/views/posts/_post.html.erb which causes problem is:
<%= div_for post do %>
<%= link_to post.user.username, post.user %>
posted
<%= render post.content %>
<%= link_to time_ago_in_words(post.created_at), post %>
<% end %>
Sorry if the details I provide is insufficient, I am a new ROR developer. If you want, you can fork or check the project from here, (I pushed so you can check for the error).
Any help/guidance is greatly appreciated!
Please try
<%= render post.content if post.content %>
instead of
<%= render post.content %>
as per the error logs, this should fix the issue.

Refactoring into partials in 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.

passing variable into partial

I have the following for and partial setup but i keep on getting an error, that the partial does not recognise the variable |builder|.
Form
<%= simple_form_for #firm do |f| %>
<%= f.fields_for :events do |builder| %>
<%= render 'event_fields', :builder => builder %>
<% end %>
<%= end %>
_events_fields partial
<fieldset>
<%= builder.input :name, :collection => ['Applications Open', 'Applications Close', 'Traineeship Starts'] %>
<%= builder.text_field :start_at, :class => 'datepicker' %>
<%= builder.hidden_field :all_day, :value => true %>
<%= link_to "remove", '#', class: "remove_fields" %>
any idea how i should be padding the variable across? or if in fact this is the correct way of doing it? It would be really helpful is someone could help me understand a little more about how and why you need to do this.
You need to tell it that it is a partial view and pass in a hash to the locals option. Like so:
<%= simple_form_for #firm do |f| %>
<%= f.fields_for :events do |builder| %>
<%= render partial: 'event_fields', locals: {builder: builder} %>
<% end %>
<% end %>
If you're using Ruby 1.8 then:
<%= simple_form_for #firm do |f| %>
<%= f.fields_for :events do |builder| %>
<%= render :partial => 'event_fields', :locals => { :builder => builder } %>
<% end %>
<% end %>
partial_name would be replace with actual partial name or partial name with directory name.
We would provide the data_object object to the partial, available under the local variable data_variable in the partial and is equivalent to:
<%= render partial: "partial_name", locals: { data_variable: data_object } %>

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 %>

Resources