Reputation: 3231
I am using ajax for creating post that belongs to a particular topic where I render the form in post index page. Each post can have many tags and I am also using devise authentication and CanCanCan authorization.
I need to capture the error message of the post submit and show it in the browser through this JavaScript template Create.js.erb with custom error messages instead of doing in post form.
Below is the code:
Post controller
class PostsController < ApplicationController
load_and_authorize_resource
before_action :set_post, only: [:show, :edit, :update, :destroy, :update_status]
skip_before_action :verify_authenticity_token
# GET /posts
# GET /posts.json
def index
if params[:topic_id].present?
@topic = Topic.find(params[:topic_id])
@posts = @topic.posts.paginate(page: params[:page], per_page: 10)
@post = @topic.posts.new
else
@posts = Post.eager_load(:topic, :user).paginate(page: params[:page], per_page: 10)
end
@tags =Tag.all
end
# GET /posts/1
# GET /posts/1.json
def show
@tags = @posts.tags
end
def update_status
current_user.posts<<(@posts)
end
# GET /posts/new
def new
@topic = Topic.find(params[:topic_id])
@posts = @topic.posts.new
@tags =Tag.all
end
# GET /posts/1/edit
def edit
@tags = @posts.tags
end
# POST /posts
# POST /posts.json
def create
@topic = Topic.find(params[:topic_id])
@posts = @topic.posts.create(post_params)
respond_to do |format|
@posts.user_id = current_user.id
if @posts.save
format.html { redirect_to topic_posts_path(@topic), notice: 'Post was successfully created.' }
format.js
format.json { render :show, status: :created, location: @posts }
else
format.html { render :new }
format.json { render json: @posts.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /posts/1
# PATCH/PUT /posts/1.json
def update
@tags = @posts.tags
respond_to do |format|
if params[:rate].to_i>0
@posts.ratings.create(:star => params[:rate])
format.html { redirect_to post_path(@posts), notice: 'Rating was successfully updated.' }
elsif @posts.update(post_params)
format.html { redirect_to post_path(@posts), notice: 'Post was successfully updated.' }
format.json { render :show, status: :ok, location: @posts }
else
format.html { render :edit }
format.json { render json: @posts.errors, status: :unprocessable_entity }
end
end
end
# DELETE /posts/1
# DELETE /posts/1.json
def destroy
@posts.destroy
respond_to do |format|
format.html { redirect_to topic_posts_url(@posts.topic_id), notice: 'Post was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_post
@posts = Post.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def post_params
params.require(:post).permit(:image, :name, :message, :topic_id, {tag_ids:[]}, :rate, :user_id)
end
protected
def json_request?
request.format.json?
end
end
post form
<%= form_for [@topic, @post], remote: true do |f| %>
<% if @post.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@post.errors.count, "error") %> prohibited this post from being saved:</h2>
<ul>
<% @post.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<div class="field">
<%= f.label :Image %><br>
<%= f.file_field :image %>
</div>
<div class="field">
<%= f.label :Name %><br>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :Message %><br>
<%= f.text_area :message %>
</div>
<% if @tags %>
<% @tags.each do |tag| %>
<div>
<%= check_box_tag "post[tag_ids][]", tag.id, @post.tags.include?(tag) %>
<%= tag.name %>
</div>
<% end %>
<% end %>
<br><br>
<%= link_to 'Create Tag', tags_path %>
<br><br>
<%= f.submit %>
<% end %>
create.js.erb
$("#post_table").append("<%= j render @posts %>");
alert("Post created")
index.html.erb
<p id="notice"><%= notice %></p>
<div id='ajax_loader' style="position: absolute; left: 50%; top: 50%; display: none;">
<%= image_tag "ajax-loader.gif" %>
</div>
<script>
$(document).ajaxStop(function(){
$("#ajax_loader").hide();
});
$(document).ajaxStart(function(){
$("#ajax_loader").show();
});
</script>
<%= will_paginate %>
<h1>Listing Posts</h1>
<table id = "post_table">
<thead>
<tr>
<th><th>Name</th></th>
<th><th>Author</th></th>
<th><th>Message</th></th>
<th><th>Status</th></th>
<th colspan="4"></th>
</tr>
</thead>
<tbody>
<%= render @posts %>
</tbody>
</table>
<br>
<% if @topic %>
<%= link_to 'New Post', "#", id: "new_post" %>|
<section id = "new_post_section">
<%= render 'form' %>
</section>
<%= link_to 'Back to Topics', topic_path(@topic) %>
<% else %>
<% link_to 'New Post', new_post_path %>
<% end %>
<%= will_paginate %>
Post model
class Post < ActiveRecord::Base
belongs_to :user
belongs_to :topic
has_many :comments
has_and_belongs_to_many :tags
has_many :ratings
validates_presence_of :name, :presence => true
validates_length_of :name, maximum: 5
has_attached_file :image
#validates_attachment_presence :image, :presence => true
validates_attachment_content_type :image, :content_type => ['image/jpeg', 'image/png']
validates_attachment_size :image, :in => 0..100.kilobytes
end
Please help me.
Upvotes: 3
Views: 7037
Reputation: 3985
Modify your the create
action in the posts_controller.rb
to something like this (notice that format.js
was added to the else
clause of the respond_to
block):
# POST /posts
# POST /posts.json
def create
@topic = Topic.find(params[:topic_id])
@posts = @topic.posts.create(post_params)
respond_to do |format|
@posts.user_id = current_user.id
if @posts.save
format.html { redirect_to topic_posts_path(@topic), notice: 'Post was successfully created.' }
format.js
format.json { render :show, status: :created, location: @posts }
else
format.html { render :new }
format.js # call create.js.erb on save errors
format.json { render json: @posts.errors, status: :unprocessable_entity }
end
end
end
Then, in create.js.erb
you can check for errors and handle them however you'd like. Example:
<% if @post.errors.any? %>
alert("ERROR(S): <%= j @post.errors.full_messages.join('; ') %>")
<% else %>
$("#post_table").append("<%= j render @posts %>");
alert("Post created");
<% end %>
Upvotes: 7