Create.js.erb Javascript asking for partial - javascript

I'm trying to get my my create action to work in my rails app. When I have these two lines
$('#pit_form').remove(); //remove form
$('#new_link').show(); //show new link again
it functions properly, and removes the form plus adds the link back, but I can't show the new pit with my escape. I've tried a few things but it always gives me this error
ActionView::Template::Error (Missing partial pits/_pit with {:locale=>[:en], :formats=>[:js, :html], :variants=>[], :handlers=>[:erb, :builder, :raw, :ruby, :jbuilder, :coffee]}. Searched in:
* "/Users/markhustad/projects/fire_2/app/views"
* "/usr/local/rvm/gems/ruby-2.1.1/gems/devise-3.2.4/app/views"
):
1: $('#pit_form').remove(); //remove form
2: $('#new_link').show(); //show new link again
3: $('#pit_index').append(<%= j (render(#pit)) %>);
app/views/pits/create.js.erb:3:in `_app_views_pits_create_js_erb___3365989432298988625_2214355520'
app/controllers/pits_controller.rb:20:in `create'
when I add this line or something similar(not sure why I need _pit partial)
$('#pit_index').append(<%= j (render(#pit)) %>);
My pits controller currently
class PitsController < ApplicationController
before_action :current_user, only: [:create, :destroy]
before_action :correct_user, only: :destroy
def new
#pit = Pit.new
end
def index
#pit = Pit.all
#user = User.find_by(params[:id])
#pits = Pit.paginate(:page => params[:page]).order('created_at DESC').group_by { |pit| pit.created_at.strftime("%B %Y") }
end
def create
#pit = current_user.pits.create(pit_params)
respond_to do |format|
format.html { redirect_to pits_path}
format.js
end
end
def show
#pit = Pit.find(params[:id])
end
def edit
end
def update
#pit = Pit.find(pit_params[:id])
if #pit.update_attributes(pit_params)
redirect_to #pit
end
end
def destroy
#pit = Pit.find(params[:id])
#pit.destroy
end
def upvote
#pit = Pit.find(params[:pit_id])
#pit.upvote_from current_user
redirect_to pit_path(#pit)
end
def downvote
#pit = Pit.find(params[:pit_id])
#pit.downvote_from current_user
redirect_to pit_path(#pit)
end
private
def correct_user
#pit = current_user.pits.find_by_id(params[:id])
redirect_to root_path if #pit.nil?
end
def pit_params
params.require(:pit).permit(:topic, :summary, :image, :video_url, :author, :user_id)
end
end
Pits index
<div class = "container list-pits">
<%= link_to "Add New Pit", new_pit_path, id: "new_link", remote: true, class: "btn btn-default" %>
<br>
<br>
<% #pit.each do |pit| %>
<div class = "container">
<div class = "well", id = "pit_index">
<h3 id="pit-title"><%= link_to pit.topic, pit_path(pit) %></h3>
<p>by <%= link_to pit.author, '#' %></p>
<br>
<p><%= pit.summary %></p>
<p>Replies (<%= pit.comments.count %>)</p>
<br>
<p>Pit Created by: <%= link_to pit.user.name, pit.user %> on <%= pit.created_at %></p>
<%= link_to "View Pit", pit_path(pit), class: "btn btn-primary" %>
<%= link_to "Delete Pit", pit_path(pit), remote: true, method: :delete, data: { confirm: 'Are you sure?' } %>
</div>
</div>
<% end %>
</div>
_form in Pits
<div class="container new-pit">
<%= render 'devise/shared/error_messages', obj: #pit %>
<%= form_for #pit, remote: true, :html => {:multipart => true} do |f| %>
<div class = "form-horizontal", id = "pit_form">
<div class="form-group">
<%= f.label :topic, class: "col-sm-2 control-label" %>
<div class="col-sm-6">
<%= f.text_field :topic, class: "form-control", autofocus: true %>
</div>
</div>
<div class="form-group">
<%= f.label :author, class: "col-sm-2 control-label" %>
<div class="col-sm-6">
<%= f.text_field :author, class: "form-control", :placeholder => "Enter name of book author, lecturer, or presenter" %>
</div>
</div>
<div class="form-group">
<%= f.label :summary, class: "col-sm-2 control-label" %>
<div class="col-sm-6">
<%= f.text_area :summary, class: "form-control", :placeholder => "Present an argument for or against the material presented and state why you think it is accurate or not" %>
</div>
</div>
<div class="form-group">
<%= f.label :image, class: "col-sm-2 control-label" %>
<div class="col-sm-6">
<%= f.file_field :image, class: "form-control" %>
</div>
</div>
<div class="form-group">
<%= f.label :video, class: "col-sm-2 control-label" %>
<div class="col-sm-6">
<%= f.text_field :video_url, class: "form-control", :placeholder => "example: //www.youtube.com/embed/hBHYdK9xtYs (video is optional)" %>
<p class = "youtube-instruction">Must use the shared -> embed option</p>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-6">
<%= f.submit "Start Pit", class: "btn btn-primary" %>
</div>
</div>
</div>
</div>
</div>
<% end %>
I know I'm close here but need a bit more direction. Thanks.

You need two things. First, a pit.js.erb file that has:
$('#pit_form').remove();
$('#new_link').show();
$('#pit_index').append(<%= j (render(#pit)) %>);
I think you already have this.
You also need a _pit.html.erb file under the /pits folder that describes the layout of individual pit items on the pit index.
The order of operations goes like this:
Send a create request via Ajax. On forms, this is typically done with the remote: true option, which uses Unobstrusive JavaScript.
Process the response in the controller's create action using format.js. By default, this renders the .js.erb file that corresponds to the action name (i.e. create.js.erb).
Inside this js.erb file, you can also embed more render commands. In your specific case, you are trying to render a _pit.html.erb or a _pit.js.erb template, both of which are missing.
If you already have the pit template in a specific folder, you can specify it in the render action, like this:
$('#pit_index').append("<%= j (render 'myfolder/pit') %>");
I hope this helps.

Related

Rails + Javascript: Create one parent model and multiple child model in same time

I have a parent model (paper) and a nested child model (tape) and want to create multiple child with a parent in same time without using any gems.
The input fields of tape should be dynamically added through clicking “+”.
If I write “3.times { #paper.tapes.build }” in controller, I can create 1 paper and 3 tapes in same time.
But if how many times the input field should be added is depend on the user (if user click "+" 10 times, 1 parent model and 10 child model should be saved in one time), how should I modify the code?
Here is my codes.
Paper Model
has_many :tapes
accepts_nested_attributes_for :tapes, allow_destroy: true
Tape Model
belongs_to :paper, optional: true
Controller
def new
#paper = Paper.new
3.times { #paper.tapes.build }
end
def create
#paper = Paper.new(paper_params)
#paper.user_id = current_user.id
if #paper.save
redirect_to action_list_paper_path(#paper.id)
else
render 'new'
end
end
Viewer
<%= nested_form_for(#paper) do |f| %>
<div class="container">
<%= stylesheet_link_tag 'papers', media: 'all', 'data-turbolinks-track': 'reload' %>
<div class= "paper_form">
<div class="col-md-6">
<%= f.label(:content, "Name") %>
<%= f.text_area :content %>
</div>
</div>
</div>
<div class="tape_form">
<%= f.fields_for :tapes do |tape| %>
<div id="input_pluralBox">
<div id="input_plural">
<div class="col-md-4">
<%= tape.label :label %>
<%= tape.text_field :label %>
</div>
</div>
<input type="button" value="+" class="add pluralBtn">
<input type="button" value="-" class="del pluralBtn">
</div>
</div>
<% end %>
</div>
</div>
<% end %>
Javascript (The input column “label” will be added with "+" through javascript).
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script type="text/javascript">
$(document).on("click", ".add", function() {
$(this).parent().clone(true).insertAfter($(this).parent());
});
$(document).on("click", ".del", function() {
var target = $(this).parent();
if (target.parent().children().length > 1) {
target.remove();
}
});
</script>
An example of how to add nested records in a form:
<%= form.fields_for :headers, get_headers(client) do |builder| %>
<div>
<div class="header-fields form-row">
<%= builder.hidden_field :id %>
<div class="form-group col col-md-4">
<%= builder.label :key %>
<%= builder.text_field :key, class: 'form-control' %>
</div>
<div class="form-group col col-md-6">
<%= builder.label :value %>
<%= builder.text_field :value, class: 'form-control', value: builder.object.value %>
</div>
<% if action_name == "edit" %>
<div class="form-group col col-md-2">
<div class="form-check">
<%= builder.check_box :_destroy, class: 'form-check-input' %>
<%= builder.label :_destroy, "Destroy?", class: 'form-check-label' %>
</div>
</div>
<% end %>
</div>
</div>
<% end %>
Helper function
def get_headers(client)
return client.headers if client.headers.any?
[Header.new]
end
Controller params
def client_params
params.require(:client).permit(headers_attributes: [:id, :key, :value, :_destroy])
end
Model:
class Client < ApplicationRecord
has_many :headers, dependent: :destroy
accepts_nested_attributes_for :headers, allow_destroy: true
end
Then JS as required for adding / removing rows.

How to display validation error in rails using AJAX

I need to display the validation error of my post model. I have used AJAX call to create a post into the index page of the post. So that when the NewPost button is clicked it will display the new post form partial into the index page. While creating the post in index page if there is any validation errors found, the errors are displayed and it renders the new post form partial in js format again so that the new post form appears twice along with the validation error.
Posts controller:
def create
#post = #topic.posts.build(post_params)
#post.user = current_user
respond_to do |format|
if #post.save
# Success
else
format.js { render 'posts/new' }
end
end
end
Create.js.erb file:
alert("Post created Successfully");
$('.new_post').hide();
$('.new_one').show();
$('.post_div').prepend('<%= j render #post %>');
Index.html.erb file:
<div class="container" >
<% if params[:topic_id].present? %>
<h2 align="center"><span class="em-text"><%= #topic.topicname %> Posts</span></h2><hr>
<%= link_to "New Post", new_topic_post_path, :class => 'btn btn-primary new_one' ,remote: true%> <br><br><br>
<% else %>
<h2 align="center"><span class="em-text">All Posts</span></h2><hr>
<% end %>
<div class="post_div">
<%= render #posts %>
</div>
<%= will_paginate #posts, renderer: BootstrapPagination::Rails %>
</div>
Post partial for new post form:
<%= form_for [#topic, #post],remote: true,html: {multipart: true}, url: topic_posts_path do |f| %>
<% if #post.errors.any? %>
<% #post.errors.full_messages.each do |msg| %>
<div class="alert alert-danger"><%= msg %></div>
<% end %>
<% end %>
<div class="form-group">
<%= f.label "Title" %><br/>
<%= f.text_field(:title,{:class => 'form-control', :placeholder => 'Enter the Title'}) %>
</div>
<div class="form-group">
<%= f.label "Body" %><br/>
<%= f.text_area(:body, {:class => 'form-control', :placeholder => 'Enter the Post Body'}) %>
</div>
<div class="form-group">
<%= f.submit({:class => 'btn btn-primary'})%>
</div>
<% end %>
new.js.erb file:
$('.new_one').hide().after("<%= j render 'form' %>")
Use can like this
<% if #post.errors.any? %>
alert("ERROR(S):\n<%= j #post.errors.full_messages.join("\n") %>")
Check the post whether it has any errors if error exists alert the error else do something

Adding search function within form

I am adding a search function within another form. I would like to search through the things within the other form.
Interest_index.html.erb
<%= form_for :interest, url: interest_index_path do |f| %>
<p class="col-md-8" align="left"><%= f.submit "Save Schedule", class: "btn btn-primary btn-lg btn-block"%></p>
<br>
<div class="field form-group col-lg-12">
<h1><%= f.label :interests, "Schedule" %></h1>
<br>
<div class="row inline">
<%= form_tag interest_index_path, method: :get do %>
<p>
<div class="col-lg-offset-2 col-lg-7" id="one">
<%= text_field_tag :search, params[:search], class: "form-control", placeholder: "Search" %>
</div>
<div id="two">
<%= submit_tag "Search", name: nil, class: "btn btn-default" %>
</div>
</p>
<% end %>
</div>
<% #subjects.each do |subject| %>
<div class="field">
<p><h4><%= f.check_box :interests, {:multiple => true}, subject.id, nil %><%= subject.name %></h4></p>
</div>
<% end %>
</div>
<% end %>
I have the search form within a bigger form to search through the subjects which will be chosen and then submitted with the main form. I have tried using basic search as i a new to rails but it does not work.
I think usually to have a form within a form you would need to make nested attributes, but this being a search form I am not sure how to do that or whether that would work.
Also the way i have it set up is I have created a lot of subjects which will be displayed under the interests index. Under interests the user picks the subjects of their interests
here are the controllers and models
Interests_controller
class InterestController < ApplicationController
def index
if params[:query].present?
#subjects = Subject.search(params[:query], load: true)
else
#subjects = Subject.all.sort_by(&:name)
end
end
def create
current_user.interests = params[:interests].to_json
if current_user.save
else
flash[:danger] = "Something went wrong!"
end
redirect_to interest_index_path
end
end
** Interest Model**
class Interest < ActiveRecord::Base
searchkick
include Tire::Model::Search
include Tire::Model::Callbacks
def self.search(search)
if search
where('name LIKE ?', "%#{search}")
else
scoped
end
end
end
Subject model
class Subject < ActiveRecord::Base
has_many :posts
has_many :users, through: :posts
validates_presence_of :name
validates_uniqueness_of :name
end
Subject_controller
class SubjectController < ApplicationController
def index
#subject = Subject.all.includes(:posts => [:user])
#interests_array = []
if current_user.interests != "null"
JSON.parse(current_user.interests).each do |f|
if Subject.find(f)
#interests_array.push(Subject.find(f))
end
end
end
end
end
Got it, there was no need for nested forms. I was also working with the wrong model.

Saving Nested Data Before Parent is Assigned an ID

I have a Resume model and an Education model. Education belongs_to resume and resume has_many educations.
I'm currently using a form in Resume's show.html.erb view to enter data for educations just to make sure it works.
In my routes.rb file I have:
resources :resumes do
resources :educations
end
In my educations_controller.rb file I have this:
def create
#resume = Resume.find(params[:resume_id])
#education = #resume.educations.build(education_params)
respond_to do |format|
if #education.save
format.html { redirect_to #resume, notice: 'Education was successfully created.' }
format.json { render :show, status: :created, location: #education }
else
format.html { render :new }
format.json { render json: #education.errors, status: :unprocessable_entity }
end
end
end
This allows me, in my views/resumes/show.html.erbto have the following:
<%= form_for [#resume,Education.new] do |f| %>
<div class="field">
<%= f.label :sectionTitle %><br>
<%= f.text_field :sectionTitle %>
</div>
<div class="field">
<%= f.label :completed %><br>
<%= f.date_select :completed %>
</div>
<div class="field">
<%= f.label :degree %><br>
<%= f.text_field :degree %>
</div>
<div class="field">
<%= f.label :school %><br>
<%= f.text_field :school %>
</div>
<div class="field">
<%= f.label :summary %><br>
<%= f.text_area :summary %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
This is currently working and allows me to enter multiple educations per Resume.
The issue is, I first have to create the resume entry before creating an education entry because the education entry depends on the resume_id integer.
How can I re structure my code so that I can create multiple education entries for a specific resume that doesn't yet have an ID so that essentially, on submit the resume is assigned an ID then any subsequent educations are attached to the given resume_id and given their own education ID?
I suspect I'll probably have to use javascript which is fine, but even so, I'm not sure what to do once intercept the default form action.
This is just little example but it works totally fine.
In routes.rb
post 'add_resume_education' => 'resumes#twince'
In resumes_controller.rb, in your case. Use your own MODEL like resume and education and change passing params too.
def twince
resume = Resume.create!(title: params[:data][:category_title])
post = resume.educations.create!(sectionTitle: params[:data][:educations][:sectionTitle])
redirect_to :back, notice: 'Yeah Created'
end
in HTML page:
<%= form_for :data, url: add_resume_education_path do |f| %>
<div class="field">
<%= f.label :category_title %>
<%= f.text_field :category_title %>
</div>
<br>
<div class="field">
<%= f.fields_for :educations do |edu| %>
<div class="field">
<%= edu.label :sectionTitle %><br>
<%= edu.text_field :sectionTitle %>
</div>
<% end %>
</div>
<br>
<%= f.submit 'create' %>
<% end %>
Also here quite good source, Nested Form

Rails & JQuery: Invalid association. Make sure that accepts_nested_attributes_for is used for

Although I'd like to add link_to_add with using simple_nested_form_for, the following error was displayed.
ArgumentError (Invalid association. Make sure that accepts_nested_attributes_for is used for :events association.):
There are similar questions in stackoverflow, but it doesn't work for me. So I post this as a new question.
The error was appeared when I add f.link_to_add in _schedule_form.html.erb.
_schedule_form.html.erb
<%= f.label :title %>
<%= f.text_field :title, class: 'form-control' %>
<br>
<%= f.label :departure_date %>
<div class="input-group date" id="datetimepicker">
<%= f.text_field :departure_date, class: 'form-control' %>
<span class="input-group-addon">
<span class="glyphicon glyphicon-calendar"></span>
</span>
</div>
<script type="text/javascript">
$(function () {
$('#datetimepicker').datetimepicker({format:'MMM-DD-YYYY'});
});
</script>
<br>
<div id="room">
<%= f.simple_fields_for :rooms do |a| %>
<p class="day-number-element-selector"><b>Day <%= a.index.to_i + 1 %></b></p>
<div id="event">
<% a.simple_fields_for :events do |e| %>
<%= e.input :from %>
<% end %>
</div>
#add here!!!
<%= f.link_to_add "Add event", :events, data: {target: '#event'}, class: "btn btn-primary" %>
<%= a.input :room %>
<% end %>
</div>
new_html.erb
<div class="row">
<div class="col-md-12">
<p>Create schedule</p>
<%= simple_nested_form_for(#schedule) do |f| %>
<%= render 'schedule_form', f: f %>
<%= f.submit "Create my schedule", class: "btn btn-primary" %>
<br>
<% end %>
</div>
</div>
Give the following models:
class Schedule < ActiveRecord::Base
belongs_to :user
has_many :rooms
accepts_nested_attributes_for :rooms, allow_destroy: true
...
class Room < ActiveRecord::Base
belongs_to :schedule
has_many :events
accepts_nested_attributes_for :events, allow_destroy: true
...
class Event < ActiveRecord::Base
belongs_to :room
...
schedule_controller.rb
class SchedulesController < ApplicationController
...
before_action :set_schedule, only: %i(show edit update destroy)
...
def new
#schedule = Schedule.new
room = #schedule.rooms.build
room.events.build
end
def create
#schedule = current_user.schedules.build(schedule_params)
if #schedule.save
flash[:success] = "schedule created!"
redirect_to root_url
else
render 'new'
end
end
def edit
#day_max = Room.where("schedule_id = ?", #schedule.id).maximum(:day)
end
def update
#schedule.rooms.maximum(:day)
if #schedule.update(schedule_params)
flash[:success] = "schedule updated!"
redirect_to root_url
else
render 'edit'
end
end
private
def schedule_params
params.require(:schedule).permit(:title, :departure_date, rooms_attributes: [:id, :_destroy, :room, :day, events_attributes: [:id, :_destroy, :from, :to, :title, :detail]])
end
def set_schedule
#schedule = Schedule.find(params[:id])
end
No error have been displayed before adding link_to_add.
It would be appreciated if you could give me any suggestion.
SOLVED!!!
<div id="room">
<%= f.simple_fields_for :rooms do |a| %>
<div id="room_<%= a.object.object_id %>">
<p class="day-number-element-selector"><b>Day <%= a.index.to_i + 1 %></b></p>
<%= a.simple_fields_for :events do |e| %>
<span class="form-inline">
<%= e.input :from, label: false %>
<%= e.input :to, label: false%>
</span>
<%= e.input :title, label: 'event' %>
<% end %>
</div>
<%= a.link_to_add "Add event", :events, data: {target: "#room_#{a.object.object_id}"}, class: "btn btn-primary" %>
<%= a.input :room %>
<% end %>
</div>
div#room should be something like :
<div id="room">
<%= f.simple_fields_for :rooms do |a| %>
<p class="day-number-element-selector"><b>Day <%= a.index.to_i + 1 %></b></p>
<% a.simple_fields_for :events do |e| %>
<div id="event">
<%= e.input :from %>
</div>
<% end %>
#add here!!!
<%= a.link_to_add "Add event", :events, data: {target: '#event'}, class: "btn btn-primary" %>
<%= a.input :room %>
<% end %>
</div>
First of all nested_form gem is abandoned, so I would suggest to use cocoon which is up to date now
Also probably you attributes filtered
room_attributes: [..., events_attributes: [...]]
As your attributes for rooms should be in plural form rooms_attributes
And the last suggestion do not use multi nesting. Try to have a look on form objects pattern
Hope it helps

Categories