How to call a form from an element - ruby-on-rails

I have Post with nested elements who also have different nested form (text for this example) according to a :cat variable.
To create the texts I'm using a post method create_element with a variable (cat = 1). And I would like to call an AJAX method to render the new text created into my post form.
My problem: I don't know how to call the text nested_form created directly into my AJAX method.
My code :
Post form (posts/new):
<%= simple_form_for #post do |f| %>
<div class="elements">
<%= f.fields_for :elements do |element| %>
<%= render 'posts/element_field', f: element %>
<% end %>
</div>
<div class="btn_add_element_area">
<a href="/posts/<%=#post.id%>/create_element?cat=1" data-method="patch" data-remote="true">
<i class="fa fa-font"></i>
</a>
</div>
<%= f.submit "Publish", class: "btn" %>
<% end %>
Post form (posts/_element_field):
<div class="element_form" id="element_form<%= f.object.id %>">
<div class="undisplay">
<%= f.number_field :cat %>
</div>
<%- if f.object.cat == 1 %>
<%= f.fields_for :post_texts do |text| %>
<%= render 'posts/elements/text_field', f: text %>
<% end %>
<% end %>
</div>
Post form (posts/_text_field):
<%= f.text_area :content %>
Post controller (create_element) :
def create_element
if params[:cat] == "1"
#element = Element.create(post: #post, cat: 1)
Text.create(element: #element)
end
respond_to do |format|
format.js {render 'elements/create'}
end
end
And the AJAX method (elements/create) :
$('.elements').append("<%= j render partial: 'posts/element_field', locals: {f: #element} %>");
Error = undefined method `object'
The problem is that in the AJAX file I call the #element created for my f variable instead of calling the form of this #element.
I also tried something like that for the AJAX method, but still not working :
<% form_for(#element) do |elm| %>
$('.elements').append("<%= j render partial: 'posts/element_field', locals: {f: elm} %>");
<% end %>
Error = undefined method `element_path'
Or
<%= simple_form_for(#post) do |p| %>
<%= p.fields_for :elements, #element do |elm| %>
$('.elements').append("<%= j render partial: 'posts/element_field', locals: {f: elm} %>");
<% end %>
<% end %>
No error but nothing happen
If you have any ideas to solve that, I would really appreciate !
PS: And ideas to improve the question title are welcome !!

Related

Rails - How to access index value in partial

I am trying to use the built-in rails ajax to append an item to a list after a user fills out a form - However, I cannot target the div tag to append the new entry to: ActionView::Template::Error (undefined local variable or method 'index'
Clients/Index:
<% #clients.each_with_index do |client, index| %>
<div id="communication_pane<%= index %>">
<%= render client.communications.order(created_at: :desc) %>
</div>
<%= form_for([#clientlist, client, client.communications.build], remote: true) do |f| %>
<%= f.text_area :content, class: "form-control", id: "communication_content#{index}" %>
<%= f.submit("New Communication") %>
<% end %>
Communications/create.js.erb:
$('#communication_pane<%= index %>').prepend('<%= escape_javascript(render #communications) %>');
How can you access the index value from Clients/Index?
In your create.js.erb, there is an undefined variable index at $('#communication_pane<%= index %>')
Because there is no way the server knows about where you clicked on the client so that you have to explicitly tell the server about it. Here is an idea:
<!-- app/views/clients/index.html.erb -->
<% #clients.each_with_index do |client, index| %>
<div id="communication_pane<%= index %>">
<%= render client.communications.order(created_at: :desc) %>
</div>
<%= form_for([#clientlist, client, client.communications.build], remote: true) do |f| %>
<%= f.text_area :content, class: "form-control", id: "communication_content#{index}" %>
<!-- Letting server know the index of current form by adding a param -->
<%= hidden_field_tag :client_index, index %>
<%= f.submit("New Communication") %>
<% end %>
<% end %>
Then at your js.erb file, use params[:client_index] instead of index
# app/views/communications/create.js.erb
$('#communication_pane<%= params[:client_index] %>')
.prepend('<%= escape_javascript(render #communications) %>');
Hope this help.
I think you will have to pass index variable to your controller action as hidden_field and then display it on create.js.erb
clients/index:
<% #clients.each_with_index do |client, index| %>
<div id="communication_pane<%= index %>">
<%= render client.communications.order(created_at: :desc) %>
</div>
<%= form_for([#clientlist, client, client.communications.build], remote: true) do |f| %>
<%= f.hidden_field :index, value: index %>
<%= f.text_area :content, class: "form-control", id: "communication_content#{index}" %>
<%= f.submit("New Communication") %>
<% end %>
communications_controller
def create
#index = params[:communication][:index]
...
end
Communications/create.js.erb
$('#communication_pane<%= #index %>').prepend('<%= escape_javascript(render #communications) %>');

Reusing a partial in the same page

I have a controller with 3 objects and i want to call the same partial three time with each object
class HomeController < ApplicationController
def index
#evaluations_teams = Evaluation.eager_load(:user).where(users: {status: true}).where(team_id: current_user.student_details.last.team_id).all.order(created_at: :desc).limit 5
#evaluations_stage = Evaluation.eager_load(:user).where(users: {status: true}).where(stage_id: current_user.student_details.last.stage_id).all.order(created_at: :desc).limit 5
#evaluations_schools = Evaluation.eager_load(:user).where(users: {status: true}).where(school_id: current_user.student_details.last.school_id).all.order(created_at: :desc).limit 5
end
end
INDEX.HTML.ERB
<%= render 'home/partials/loop_areas', locals: {evaluations:#evaluations_teams} %>
<%= render 'home/partials/loop_areas', locals: {evaluations:#evaluations_stage} %>
<%= render 'home/partials/loop_areas', locals: {evaluations:#evaluations_schools} %>
Partial: home/partials/_loop_areas.html.erb
<% #evaluations.each do |evaluation| %>
<div class="div-card-infosaluno">
<div class="card-aluno"><%= evaluation.user.full_name %></div>
<div class="card-serie"><%= "#{evaluation.stage.name} · #{evaluation.school.name}" %></div>
</div>
<% end %>
This returns:
undefined method `each' for nil:NilClass
on <% #evaluations.each do |evaluation| %>
How can i do this?
You're trying to access an instance variable #evaluations in your partial but it is not defined in the controller action.
You've to instead loop through the local variable evaluations.
<%# home/partials/_loop_areas.html.erb %>
<% evaluations.each do |evaluation| %>
...
<% end %>
And your view should be
<%= render 'home/partials/loop_areas', evaluations: #evaluations_teams %>
<%= render 'home/partials/loop_areas', evaluations: #evaluations_stage %>
<%= render 'home/partials/loop_areas', evaluations: #evaluations_schools %>
You can also pass a hash to the render method but I feel it is more verbose.
<%= render partial: 'home/partials/loop_areas', locals: { evaluations: #evaluations_schools } %>
Please try the below code in Partial: home/partials/_loop_areas.html.erb
It should work as you are expecting.
<% evaluations = local_assigns[:evaluations] %>
<% evaluations.each do |evaluation| %>
<div class="div-card-infosaluno">
<div class="card-aluno"><%= evaluation.user.full_name %></div>
<div class="card-serie"><%= "#{evaluation.stage.name} · #{evaluation.school.name}" %></div>
</div>
<% end %>
Thanks.

AJAX updating todo list in Rails 3

I'm trying to convert my todo list app to use AJAX . Here is my update action of TasksController :
class TasksController < ApplicationController
def update
#list= List.find(params[:list_id])
#task=#list.tasks.find(params[:id])
#task.update_attributes(params[:task])
respond_to do |format|
format.html { redirect_to [current_user,#list], notice: 'Task completed' }
format.js
end
end
end
tasks/update.js.erb :
<% if #task.completed? %>
$('#edit_task_<%= #task.id %>').appendTo('#completed_tasks');
<% else %>
$('#edit_task_<%= #task.id %>').appendTo('#incomplete_tasks');
<% end %>
This is my lists/show.html.erb which lists out all tasks for a particular list :
<h3>Unfinished Tasks</h3>
<div class="tasks" id="incomplete_tasks">
<% #list.tasks.incomplete.each do |task| %>
<%= form_for [current_user,#list,task], remote:true do |f| %>
<%= f.check_box :completed %>
<%= f.submit %>
<%= f.label :completed, task.description %>
<% end %>
<% end %>
</div>
<h3>Finished Tasks</h3>
<div class="tasks" id="completed_tasks">
<% #list.tasks.completed.each do |task| %>
<%= form_for [current_user,#list,task], remote: true do |f| %>
<%= f.check_box :completed %>
<%= f.submit %>
<%= f.label :completed, task.description %>
<% end %>
<% end %>
<div class="tasks" id="completed_tasks">
<% #list.tasks.completed.each do |task| %>
<%= form_for [current_user,#list,task], remote: true do |f| %>
<%= f.check_box :completed %>
<%= f.submit %>
<%= f.label :completed, task.description %>
<% end %>
<% end %>
</div>
So, I don't quite understand the tasks/update.js.erb code.
$('#edit_task_').appendTo('#completed_tasks');
In the above code, from which html file are we taking the contents of this div :
Where does that div come from ? Please tell me if my question is unclear ,I'll try and rephrase it . Just to be clear , my code works , but I don't know why ?
Whenever you do a ajax request to your update method in the controller, the tasks get updated and it responds back with data in the format.js. After it responds, the update.js.erb gets called which updates the different elements in the page, from which you sent the ajax request, with the updated tasks.
In you update.js.erb,
<% if #task.completed? %>
$('#edit_task_<%= #task.id %>').appendTo('#completed_tasks');
<% else %>
$('#edit_task_<%= #task.id %>').appendTo('#incomplete_tasks');
<% end %>
there is a #task variable, which is the new task. If the task is completed, then it adds the task to the complete_tasks div - else it appends to the incomplete_tasks div.
Completed Tasks - <div class="tasks" id="completed_tasks">
Incomplete Tasks - <div class="tasks" id="incomplete_tasks">

How can I pass more than 2 arguments to partial?

I want to pass 2 arguments such as topic and icon_photo.
How can I do that?
undefined method `icon_photo?'
I got this error with the code below.
view
<div class="Topic">
<% #community.topics.each do |topic| %>
<%= render 'topics/topic', :topic => topic, :icon_photo => topic.user.profile.avatar %>
<% end %>
</div>
You can pass a locals hash:
<div class="Topic">
<% #community.topics.each do |topic| %>
<%= render 'topics/topic', locals: {topic: topic, icon_photo: topic.user.profile.avatar, etc: 'blabla' } %>
<% end %>
</div>
See some documentation here:
http://www.tutorialspoint.com/ruby-on-rails/rails-render.htm
A little improvement can be mabe, you can render your collection like this:
<div class="Topic">
<%= render partial: 'topics/topic', collection: #community.topics %>
</div>
# in your partial topics/_topic.html.erb:
<% icon_photo = topic.user.profile.avatar %>

Rails 3.1 - Extra result of each loop?

This is really simple, but i'm going slightly mad and probably missing something that's staring me in the face. Can anyone help?
Basically, I have a simple each loop that's returning an extra rogue line. Even when there's nothing in the db, I get one line returned!
My show view including the loop is:
<p id="notice"><%= notice %></p>
<p>
<b>Header:</b>
<%= #mailer.header %>
</p>
<p>
<b>Subtext:</b>
<%= #mailer.subtext %>
</p>
<div id="" class="" padding-left: 30px;>
<h3>Mailer Products </h3>
<ol id="mailer-Product-list">
<% #mailer.mailer_products.sort_by { |mailer_products| mailer_products.position }.each do |mailer_product| %>
<%= content_tag_for :li, mailer_product do %>
<%= mailer_product.product.cat_no %>
<% end %>
<% end %>
</ol>
<%#= link_to 'Done', #product, :class => "standard-button" %>
</div>
<%= form_for([#mailer,#mailer.mailer_products.build]) do |f| %>
<div class="field">
<%= f.label :product_id %><br />
<%= f.text_field :product_id %>
</div>
<div class="field">
<%= f.hidden_field :mailer_id, :value => #mailer.id %>
</div>
<div class="actions">
<%= f.submit "Add Product" %>
</div>
<% end %>
<%= link_to 'Edit', edit_mailer_path(#mailer) %> |
<%= link_to 'Back', mailers_path %>
The controller code is:
class MailersController < ApplicationController
def show
#mailer = Mailer.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render :json => #mailer }
end
end
class MailerProductsController < ApplicationController
def index
#mailer_products = MailerProduct.find(:all)
respond_to do |format|
format.html # index.html.erb
format.json { render :json => #mailer_products }
end
end
end
end
Your call to form_for looks like this
form_for([#mailer,#mailer.mailer_products.build]) do |f|
You get an extra blank item because that's what calling .build on mailer_products does: it appends a new instance to the array
When the form is after the loop this doesn't matter, but when things are the other way around the loop will be on the modified array
My usual mistake is adding a <%= instead of a <% on the loop...
<%= #foo.each do |itme| %>
# do stuff
<% end %>
which should be
<% #foo.each do |itme| %>
# do stuff
<% end %>
Double check your tags...

Resources