I would like to display my orders like the ingredients are displayed just above. And I don't understand why is not ??
Post : Ingredients nested
Onlines :Orders nested
Views/posts/show:
<p>
<strong>Title:</strong>
<%= #post.title %>
</p>
<p> Posted by : <%= link_to #post.user.pseudo, profile_path(#post.user.pseudo) %>, <%= time_ago_in_words(#post.created_at) %> ago </p>
<p>
<strong>Image:</strong>
<%= image_tag #post.image.url(:medium) %>
</p>
<p>
<strong>Description:</strong>
<%= #post.description %>
</p>
<div class="btn-group" role="group" aria-label="...">
<%= link_to '- Pusher - ', new_post_online_path(#post), data: { confirm: 'Confirmer la mise en ligne de #{#title}?' }, class: "btn btn-primary " %>
<div class="col-md-12">
<h3>Ingrédients :</h3>
<div id="ingredients">
<ul>
<%- #post.ingredients.each do |ingredient| %>
<li>
<%= ingredient.name %>
</li>
<%end%>
</ul>
</div>
</div>
<br>
<div class="col-md-9">
<h3>Parts :</h3>
<div id="ingredients">
<ul>
<%- #post.onlines.orders.each do |order| %>
<li>
<%= order.id %>
</li>
<%end%>
</ul>
</div>
</div>
<%= link_to 'Patcher', edit_post_online_path(#post, #post.onlines.last), class: "btn btn-warning"%>
</div>
post controller:
class PostsController < ApplicationController
before_action :authenticate_user!
before_action :set_post, only: [:show, :edit, :update, :destroy]
before_action :owned_post, only: [:edit, :update, :destroy]
# GET /posts
# GET /posts.json
def index
#posts = Post.push_posts
end
# GET /posts/1
# GET /posts/1.json
def show
end
# GET /posts/new
def new
#post = current_user.posts.build
end
# GET /posts/1/edit
def edit
end
# POST /posts
# POST /posts.json
def create
#post = current_user.posts.build(post_params)
respond_to do |format|
if #post.save
format.html { redirect_to #post, notice: 'Post was successfully created.' }
format.json { render :show, status: :created, location: #post }
else
format.html { render :new }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /posts/1
# PATCH/PUT /posts/1.json
def update
respond_to do |format|
if #post.update(post_params)
format.html { redirect_to #post, notice: 'Post was successfully updated.' }
format.json { render :show, status: :ok, location: #post }
else
format.html { render :edit }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
# DELETE /posts/1
# DELETE /posts/1.json
def destroy
#post.destroy
respond_to do |format|
format.html { redirect_to posts_url, 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
#post = 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(:user_id, :title, :description, :image, ingredients_attributes: [:id, :name, :_destroy])
end
def owned_post
unless current_user == #post.user
flash[:alert] = "That post doesn't belong to you!"
redirect_to root_path
end
end
def set_online
#onlines = Online.find_by(params[:id])
end
end
Onlines controller:
class OnlinesController < ApplicationController
before_action :authenticate_user!
before_action :set_post
before_action :owned_online, only: [:new, :update]
before_action :set_online
def new
#online = current_user.onlines.build
#online.post_id = #post.id
#online.user_id = current_user.id
end
def edit
end
def taked
#online.orders.update(taked: false)
end
def create
if Online.where(post_id: params[:post_id]).any?
#online = Online.where(post_id: params[:post_id]).last.update_attributes(push: false)
end
#online = #post.onlines.create(online_params)
if #online.save
if #online.portion <= 0
#online.update(push: false)
flash[:success] = 'Veuillez indiquer le nombre de parts disponibles '
redirect_to root_path
else
#online.update(pushed_at: Time.zone.now)
#online.update(push: true)
flash[:success] = 'Votre post est en ligne !'
redirect_to root_path
end
else
render 'new'
end
end
def update
if #onlines.update(online_params)
if #online.push == false
if #online.portion <= 0
#online.update(push: false)
flash[:success] = 'Veuillez indiquer le nombre de parts disponibles '
redirect_to root_path
else
#online.update(push: true)
flash[:success] = 'Votre post a bien été pushé !'
redirect_to root_path
end
end
else
#user.errors.full_messages
flash[:error] = #user.errors.full_messages
render :edit
end
end
private
def online_params
params.require(:online).permit(:user_id, :post_id, :prix, :portion, :push, :pushed_at, orders_attributes: [:id, :taked, :taked_at, :taked_by, :validated_at, :validated_by, :_destroy])
end
def owned_online
#post = Post.find(params[:post_id])
unless current_user == #post.user
flash[:alert] = "That post doesn't belong to you!"
redirect_to :back
end
end
def set_post
#post = Post.find_by(params[:post_id])
end
def set_online
#post = Post.find(params[:post_id])
#online = Online.find_by(params[:id])
end
end
models
online :
class Online < ActiveRecord::Base
belongs_to :post
belongs_to :user
has_many :orders
accepts_nested_attributes_for :orders, allow_destroy: true
scope :push, ->{ where(push: true).order("pushed_at DESC") }
end
orders :
class Order < ActiveRecord::Base
belongs_to :online
belongs_to :user
end
and post :
class Post < ActiveRecord::Base
belongs_to :user
has_many :onlines, dependent: :destroy
scope :push_posts, lambda { joins(:onlines).merge(Online.push) }
has_many :ingredients, dependent: :destroy
accepts_nested_attributes_for :ingredients, reject_if: :all_blank, allow_destroy: true
has_many :comments
validates :image, presence: true
has_attached_file :image, styles: { medium: "300x300#"}, default_url: "/images/:style/missing.png"
validates_attachment_content_type :image, content_type: /\Aimage\/.*\Z/
end
So if you have the solution above, I'll take it !!
Thanks
Your Posts have many Onlines. Each Online has many Orders. So, you should iterate through each order of each online in your post.
<ul>
<%- #post.onlines.each do |online| %>
<%- online.orders.each do |order| %>
<li>
<%= order.id %>
</li>
<%end%>
<%end%>
</ul>
Related
In my blog app, there are posts and each post can optionally have tags. When the user is on the new or edit post form, they currently have the means to select or deselect tags to associate with the post. There is a many-to-many relationship between the post and tag models and I am using bootstrap, bootstrap_form and bootstrap-select. This all works seemingly very well. The problem is, when the user is assigning tags to their post, these tags currently have to already exist (otherwise they would have to abort their post and go add tags...bad user experience). I am trying to devise a way to give the user the option to create new tags and/or select already-existing tags and apply them to the post, all on the same post form in the collection_select field, all at the same time.
Apparently I'm asking the wrong questions on google...wouldn't this be a common need, already solved?
I am asking for guidance in providing an 'add new tag' functionality to an otherwise functional collection_select field. How best to go about this?
Posts Controller:
class PostsController < ApplicationController
before_action :set_post, only: %i[edit update interim destroy]
# GET /posts
# GET /posts.json
def index
if user_signed_in? && current_user.admin_role
if params[:tag]
#posts = Post.tagged_with(params[:tag]).all.order('updated_at DESC').page params[:page]
else
#posts = Post.all.order('updated_at DESC').page params[:page]
end
else
if params[:tag]
#posts = Post.tagged_with(params[:tag]).where(published: true).order('updated_at DESC').page params[:page]
else
#posts = Post.where(published: true).order('updated_at DESC').page params[:page]
end
end
end
# GET /posts/new
def new
#post = current_user.posts.build
#categories = Category.pluck(:name, :id)
end
# GET /posts/1/edit
def edit
#categories = Category.pluck(:name, :id)
#cat = #post.category_id
end
# POST /posts
# POST /posts.json
def create
#post = current_user.posts.create(post_params)
respond_to do |format|
if #post.save
if params[:interim]
format.html { redirect_to edit_post_path(#post), notice: 'Post was successfully created.' }
format.json { redirect_to edit_post_path(#post), status: :created, location: #post, notice: 'Post was successfully created.' }
elsif params[:complete]
format.html { redirect_to #post, notice: 'Post was successfully created.' }
format.json { render :show, status: :created, location: #post }
end
else
format.html { render :new }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /posts/1
# PATCH/PUT /posts/1.json
def update
respond_to do |format|
if #post.update(post_params)
if params[:interim]
format.html { redirect_to edit_post_path(#post), notice: 'Post was successfully updated.' }
format.json { redirect_to edit_post_path(#post), status: :ok, location: #post, notice: 'Post was successfully updated.' }
elsif params[:complete]
format.html { redirect_to #post, notice: 'Post was successfully updated.' }
format.json { render :show, status: :ok, location: #post }
end
else
format.html { render :edit }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
# DELETE /posts/1
# DELETE /posts/1.json
def destroy
#post.destroy
respond_to do |format|
format.html { redirect_to posts_url, notice: 'Post was successfully destroyed.' }
format.json { head :no_content }
end
end
private
def set_post
#post = Post.find(params[:id])
end
def post_params
params.require(:post).permit(:title, :content, :user_id, :published, :category_id, :tag_list, :tag, { tag_ids: [] }, :tag_ids,
comment_attributes: [:id, :title, :user_id, :content, :post_id, :parent_id, :ancestry, :commentable, :commentable_id, :commentable_type])
end
end
No tags controller (not needed thus far)
Post Model:
class Post < ApplicationRecord
has_many :taggings
has_many :tags, through: :taggings
has_rich_text :content
include PgSearch::Model
multisearchable :against => [:title, :content]
def self.published(post)
post.published
end
def self.tagged_with(name)
Tag.find_by!(name: name).posts
end
def self.tag_counts
Tag.select('tags.*, count(taggings.tag_id) as count').joins(:taggings).group('taggings.tag_id')
end
def tag_list
tags.map(&:name).join(', ')
end
def tag_list=(names)
self.tags = names.split(',').map do |n|
Tag.where(name: n.strip).first_or_create!
end
end
end
Tag Model:
class Tag < ApplicationRecord
has_many :taggings
has_many :posts, through: :taggings
end
Tagging Model:
class Tagging < ApplicationRecord
belongs_to :tag
belongs_to :post
end
Post Form Partial (the actual new and edit views do nothing but render this form):
<%= bootstrap_form_for #post, local: true, html: { class: 'form-horizontal' } do |f| %>
<%= f.text_field :title %>
<%= f.rich_text_area :content, control_class: 'trix-content-edit' %>
<%= f.collection_select :category_id, Category.all, :id, :name %>
<%= f.form_group :published, label: { text: "Publication Status" } do %>
<%= f.radio_button :published, true, label: "Published" %>
<%= f.radio_button :published, false, label: "Draft" %>
<% end %>
<%= f.collection_select :tag_ids, Tag.order(:name), :id, :name, {label: 'Tags', include_blank: true}, {class: 'selectpicker show-tick', multiple: 'multiple', title: 'Make your selection...', 'data-live-search': 'true', 'data-actions-box': 'true'} %>
<br><br>
<%= f.submit "Save and Resume Editing", name: "interim", class: "btn btn-primary" %>
<%= f.submit "Save and Quit", name: "complete", class: "btn btn-primary" %>
<br><br>
<% end %>
No forms for tag at this time.
I'm new in RoR, and I'm trying to practice building a web app. I have a classic app with User who have Post.
An other model Online is used to put the post on a common wall, and it's associated with a nested form Orders which represents pieces available.
So now, I'm trying to update that nested form (orders) with a button in my post show view. But it return me an error "No route matches [POST]"
while I write a PUT. So why he thinks that I want to make a new order (POST) ? And how can I change that ?
My code :
routes :
Rails.application.routes.draw do
get 'profiles/show'
mount RailsAdmin::Engine => '/admin', as: 'rails_admin'
devise_for :users, :controllers => { registrations: 'registrations' }
resources :posts do
resources :comments
resources :onlines do
resources :orders
end
end
get ':pseudo', to: 'profiles#show', as: :profile
get ':pseudo/edit', to: 'profiles#edit', as: :edit_profile
patch ':pseudo/edit', to: 'profiles#update', as: :update_profile
put 'online/:id/taked', to: 'onlines#taked', as: :taked_online
root 'posts#index'
Views/posts/show :
<div class="col-md-9">
<h3>Orders :</h3>
<div id="Orders">
<ul>
<%- #post.onlines.each do |online| %>
<%- online.orders.each do |order| %>
<%- if order.taked == false %>
<li>
<%= link_to 'Take', taked_online_path(online), method: :update, class: "btn btn-warning"%>
</li>
<%end%>
<%end%>
<%end%>
</ul>
</div>
</div>
and my Online controller :
before_action :set_post
before_action :owned_online, only: [:new, :update]
before_action :set_online, except: [:taked]
before_action :set_unline, only: [:taked]
def new
#online = current_user.onlines.build
#online.post_id = #post.id
#online.user_id = current_user.id
end
def edit
end
def taked
#online.orders.update(taked: true, taked_at: Time.zone.now, taked_by: current_user)
end
def create
if Online.where(post_id: params[:post_id]).any?
#online = Online.where(post_id: params[:post_id]).last.update_attributes(push: false)
end
#online = #post.onlines.create(online_params)
if #online.save
if #online.portion <= 0
#online.update(push: false)
flash[:success] = 'Veuillez indiquer le nombre de parts disponibles '
redirect_to root_path
else
#online.update(pushed_at: Time.zone.now)
#online.update(push: true)
flash[:success] = 'Votre post est en ligne !'
redirect_to root_path
end
else
render 'new'
end
end
def update
if #onlines.update(online_params)
if #online.push == false
if #online.portion <= 0
#online.update(push: false)
flash[:success] = 'Veuillez indiquer le nombre de parts disponibles '
redirect_to root_path
else
#online.update(push: true)
flash[:success] = 'Votre post a bien été pushé !'
redirect_to root_path
end
end
else
#user.errors.full_messages
flash[:error] = #user.errors.full_messages
render :edit
end
end
private
def online_params
params.require(:online).permit(:user_id, :post_id, :prix, :portion, :push, :pushed_at, orders_attributes: [:id, :taked, :taked_at, :taked_by, :validated_at, :validated_by, :_destroy])
end
def owned_online
#post = Post.find(params[:post_id])
unless current_user == #post.user
flash[:alert] = "That post doesn't belong to you!"
redirect_to :back
end
end
def set_post
#post = Post.find_by(params[:post_id])
end
def set_online
#post = Post.find(params[:post_id])
#online = Online.find_by(params[:id])
end
def set_unline
#online = Online.find_by(params[:id])
end
end
Models :
Post :
class Post < ActiveRecord::Base
belongs_to :user
has_many :onlines, dependent: :destroy
scope :push_posts, lambda { joins(:onlines).merge(Online.push) }
has_many :ingredients, dependent: :destroy
accepts_nested_attributes_for :ingredients, reject_if: :all_blank, allow_destroy: true
has_many :comments
validates :image, presence: true
has_attached_file :image, styles: { medium: "300x300#"}, default_url: "/images/:style/missing.png"
validates_attachment_content_type :image, content_type: /\Aimage\/.*\Z/
end
Online:
class Online < ActiveRecord::Base
belongs_to :post
belongs_to :user
has_many :orders
accepts_nested_attributes_for :orders, allow_destroy: true
scope :push, ->{ where(push: true).order("pushed_at DESC") }
end
& User :
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :posts, dependent: :destroy
has_many :onlines, dependent: :destroy
has_many :comments
has_many :orders, dependent: :destroy
validates :pseudo, presence: true, length: { minimum: 4, maximum: 16 }
has_attached_file :avatar, styles: { medium: '100x100#' }
validates_attachment_content_type :avatar, content_type: /\Aimage\/.*\Z/
end
Error :
Well, so if you have any advices for that, I'll take it !! Thanks
No route matches [POST]
In your link_to, you have method: :update which is wrong. You need to change it to below
<%= link_to 'Take', taked_online_path(online), method: :put, class: "btn btn-warning"%>
I came across a problem in my web app.
I would like to make a mvc to allow the user create a push from the post (like a ranking or commments). But actualy, the push is creating automatically when the user show the post. So I want this one is created if the user submit the data pushed.
Can you explain me where I make a mistake ?
My code
Show/post view :
<strong>Title:</strong>
<%= #post.title %>
</p>
<p>
<strong>Image:</strong>
<%= image_tag #post.image.url(:medium) %>
</p>
<p>
<strong>Prix:</strong>
<%= #post.prix %>
</p>
<p>
<strong>Description:</strong>
<%= #post.description %>
</p>
<%- if current_user.admin? %>
<div class="btn-group" role="group" aria-label="...">
<%= link_to 'Modifier', edit_post_path(#post), class: "btn btn-warning"%>
<%= link_to 'Supprimer', #post, method: :delete, data: { confirm: 'Confirmer la suppression du plat ?' }, class: "btn btn-danger" %>
<%end%>
<%=link_to "Home", posts_path, class: "btn btn-info"%>
</div>
<div class= "col-md-6">
<div class="push">
<%= render 'pushs/form' %>
</div>
</div>
Push/form (into the views/posts/show) :
<%= simple_form_for([#post, #post.pushs.build]) do |f| %>
<div class="row">
<div class="col-md-12">
<div class="form-group text-center">
<h4>Combien êtes vous ?</h4>
<%= f.text_field :quantity %>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="form-group text-center">
<h4>Ou êtes vous ?</h4>
<%= f.text_field :adress2 %>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="form-group text-center">
<%= f.button :submit %>
</div>
</div>
</div>
<% end %>
the Push controller :
class PushsController < ApplicationController
before_action :authenticate_user!
before_action :set_post
before_action :set_push, only: [:edit, :update, :destroy]
def create
#push = #post.pushs.create(push_params)
#push.user_id = current_user.id
if #push.save
flash[:success] = 'Votre commande est enregisté !'
redirect_to root_path
else
flash[:alert] = "Check the push form, something went horribly wrong."
redirect_to root_path
end
end
def update
if #push.update(push_params)
flash[:success] = 'Votre commande est enregisté !'
redirect_to root_path
else
flash[:alert] = "Check the push form, something went horribly wrong."
render 'edit'
end
end
def destroy
#push = #post.pushs.find(params[:id])
#push.destroy
flash[:success] = "Push deleted :("
redirect_to root_path
end
private
def push_params
params.require(:push).permit(:user_id, :quantity, :prix2, :time, :adress2, :latitude2, :longitude2, :taked, :taked_by, :taked_at, :validated)
end
def set_post
#post = Post.find(params[:post_id])
end
def set_push
#post = Post.find(params[:post_id])
#push = #post.pushs.find(params[:id])
end
end
& the post controller :
class PostsController < ApplicationController
before_action :authenticate_user!
before_action :set_post, only: [:show, :edit, :update, :destroy]
before_action :post_admin, only: [:new, :edit, :update, :destroy]
# GET /posts
# GET /posts.json
def index
#posts = Post.all
end
# GET /posts/1
# GET /posts/1.json
def show
end
# GET /posts/new
def new
#post = Post.new
end
# GET /posts/1/edit
def edit
end
# POST /posts
# POST /posts.json
def create
#post = Post.new(post_params)
respond_to do |format|
if #post.save
format.html { redirect_to #post, notice: 'Post was successfully created.' }
format.json { render :show, status: :created, location: #post }
else
format.html { render :new }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /posts/1
# PATCH/PUT /posts/1.json
def update
respond_to do |format|
if #post.update(post_params)
format.html { redirect_to #post, notice: 'Post was successfully updated.' }
format.json { render :show, status: :ok, location: #post }
else
format.html { render :edit }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
# DELETE /posts/1
# DELETE /posts/1.json
def destroy
#post.destroy
respond_to do |format|
format.html { redirect_to posts_url, 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
#post = Post.find(params[:id])
end
def post_admin
if current_user.admin?
else
flash[:alert] = "That post doesn't belong to you!"
redirect_to root_path
end
end
# Never trust parameters from the scary internet, only allow the white list through.
def post_params
params.require(:post).permit(:user_id, :title, :prix, :image, :description, :user_id)
end
end
Thanks, and obviously if you have any suggestions, I am eager to learn
Bye
i'm currently building a web app, and I encounters some problems.
I want the map display posts that are pushed (so push == true). For that, i'd try a lot of conditions, but it's never working. I feel I am not far from the goal, but for now, the map no reference points.
posts controller :
class PostsController < ApplicationController
before_action :authenticate_user!
before_action :set_post, only: [:show, :edit, :update, :destroy]
before_action :owned_post, only: [:edit, :update, :destroy]
# GET /posts
# GET /posts.json
def index
#posts = Post.all.order("push_updated_at DESC")
if #posts.push == true
#hash = Gmaps4rails.build_markers(#posts) do |post, marker|
marker.lat post.latitude
marker.lng post.longitude
end
end
end
# GET /posts/1
# GET /posts/1.json
def show
end
# GET /posts/new
def new
#post = current_user.posts.build
end
# GET /posts/1/edit
def edit
end
# POST /posts
# POST /posts.json
def create
#post = current_user.posts.build(post_params)
respond_to do |format|
if #post.save
#post.update(push: false)
format.html { redirect_to #post, notice: 'Post was successfully created.' }
format.json { render :show, status: :created, location: #post }
else
format.html { render :new }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /posts/1
# PATCH/PUT /posts/1.json
def update
#post = Post.find(params[:id])
respond_to do |format|
if #post.update(post_params)
format.html { redirect_to #post, notice: 'Post was successfully updated.' }
format.json { render :show, status: :ok, location: #post }
else
format.html { render :edit }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
# DELETE /posts/1
# DELETE /posts/1.json
def destroy
#post.destroy
respond_to do |format|
format.html { redirect_to posts_url, 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
#post = 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(:user_id, :title, :description, :image, :push, :push_updated_at, ingredients_attributes: [:id, :name, :_destroy])
end
def owned_post
unless current_user == #post.user
flash[:alert] = "That post doesn't belong to you!"
redirect_to root_path
end
end
end
views/posts/index :
<div class="title text-center">
<h1>Alors ? On mange quoi ?</h1>
</div>
<br>
<%= render 'map' %>
<%= render 'post' %>
& views/posts/map :
<script src="//maps.google.com/maps/api/js?v=3.18&sensor=false&client=&key=&libraries=geometry&language=&hl=®ion="></script>
<script src="//google-maps-utility-library-v3.googlecode.com/svn/tags/markerclustererplus/2.0.14/src/markerclusterer_packed.js"></script>
<script src='//google-maps-utility-library-v3.googlecode.com/svn/tags/infobox/1.1.9/src/infobox_packed.js' type='text/javascript'></script> <!-- only if you need custom infoboxes -->
<div style='width: 800px;'>
<div id="map" style='width: 800px; height: 400px;'></div>
<script type="text/javascript">
handler = Gmaps.build('Google');
handler.buildMap({ provider: {}, internal: {id: 'map'}}, function(){
markers = handler.addMarkers(<%=raw #hash.to_json %>);
handler.bounds.extendWith(markers);
handler.fitMapToBounds();
});
</script>
</div>
</div>
So if you have any suggestions about that, you're welcome !!
For this stage you should create a scope on model Post
class Post < ActiveRecord::Base
scope :push, ->{ where(push: true).order("push_updated_at DESC") }
end
and then in controller
def index
#posts = Post.push #this will fetch the post with push true and sort it
#hash = Gmaps4rails.build_markers(#posts) do |post, marker|
#rest of your code
end
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.
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 %>