I have follow and unfollow buttons for users on my application. I don't want to do anything fancy, I just want to not have the page refresh every time follow or unfollow button is clicked.
My controller
relationships_controller.rb
def create
current_user.follow(#user)
respond_to do |format|
format.html { #handle HTML, i.e. full page reload }
format.js # handle ajax request
end
end
def destroy
current_user.unfollow(#user)
respond_to do |format|
format.html
format.js # this one handle the request comes from `remote: true` button
end
end
My view
tweets/index.html.erb
<% if current_user.id != tweet.user.id %>
<% if current_user.following?(tweet.user) %>
<%= button_to "Unfollow", relationships_path(user_id: tweet.user), remote: true, method: :delete, :class => "btn btn-primary" %>
<% else %>
<%= button_to "Follow", relationships_path(user_id: tweet.user), remote: true, :class => "btn btn-primary" %>
<% end %>
<br>
<% end %>
<hr/>
<% end %>
Relationships model
relationship.rb
class Relationship < ApplicationRecord
belongs_to :follower, class_name: "User"
belongs_to :followed, class_name: "User"
validates :follower_id, presence: true
validates :followed_id, presence: true
end
User model
User.rb
has_many :active_relationships, class_name: "Relationship", foreign_key: "follower_id", dependent: :destroy
has_many :passive_relationships, class_name: "Relationship", foreign_key: "followed_id", dependent: :destroy
has_many :following, through: :active_relationships, source: :followed
has_many :followers, through: :passive_relationships, source: :follower
def follow(user)
active_relationships.create(followed_id: user.id)
end
def unfollow(user)
active_relationships.find_by(followed_id: user.id).destroy
end
def following?(user)
following.include?(user)
end
Routes
routes.rb
resource :relationships, :only => [:create, :destroy]
Application.js
require("#rails/ujs").start()
require("turbolinks").start()
require("#rails/activestorage").start()
require("channels")
require("chartkick")
require("chart.js")
//= require jquery3
//= require popper
//= require bootstrap-sprockets
Inspected button element
<form class="button_to" method="post" action="/relationships?user_id=1" data-remote="true"><input class="btn btn-primary" type="submit" value="Follow"><input type="hidden" name="authenticity_token" value="hfwF8wXBcp/OM2P/pCYBnEBrjw22BDKWbw/dZFwwDsRpiIFq5jBKS/AoTMjkCZRrGum7UyW1kaL3h/4XEM2wIg=="></form>
With this when I click follow nothing now happens. I think I need a new js file in my views but unsure how to implement it.
I have looked at solutions but they are many and varied and seeking to do more than I want to do which is just a simple no refresh.
How is this best achieved? (can provide more code if needed)
EDIT: This code got jQuery working in Rails 6 in my ..webpack/enironment.js file
# app/config/webpack/environment.js
const {environment} = require('#rails/webpacker');
const webpack = require('webpack');
environment.plugins.append('Provide', new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery' # or if its not work specify path `'jquery/src/jquery'` which node_modules path for jquery
}));
module.exports = environment;
For #max
$(document).on('ajax:success', '.follow-btn', function(event){
let $el = $(this);
let method = this.dataset.method;
if (method === 'post') {
$('.follow-btn[href="'+this.href+'"]').each(function(el){ $(el).text('Unfollow'); });
this.dataset.method = 'delete';
} else if (method === 'delete') {
$('.follow-btn[href="'+this.href+'"]').each(function(el){ $(el).text('Follow'); });
this.dataset.method = 'post';
}
});
Instead of going down the js.erb rabbit hole you can just send a JSON request and write a simple event handler.
Lets start by adding a data-type="json" attribute to the buttons so they send a request for JSON instead of javascript:
<% unless current_user == tweet.user %>
<% if current_user.following?(tweet.user) %>
<%= link_to "Unfollow", relationships_path(user_id: tweet.user),
data: { remote: true, type: :json, method: :delete },
class: "follow-btn btn btn-primary"
<% else %>
<%= link_to "Follow", relationships_path(user_id: tweet.user),
data: { remote: true, type: :json, method: :post},
class: "follow-btn btn btn-primary"
%>
<% end %>
<% end %>
And then just write JSON responses for your controller.
def create
current_user.follow(#user)
respond_to do |format|
format.html
format.json { head :created }
end
end
def destroy
current_user.unfollow(#user)
respond_to do |format|
format.html
format.json { head :no_content }
end
end
As you can see its pretty damn simple, when creating a resource you return a 201 - Created and usually a location header or the entity in the body (a JSON payload describing what was created). When you update or destroy a record a 204 - No Content status code is sufficient.
If you test it now and look at the network tab in your browser inspector you will see that an AJAX request is sent but nothing happens in the view.
So lets write an event handler that toggles the button text and method after the request was sent. Since Rails UJS already created the AJAX handler for the button for us we can just hook into its events:
// put this in your application.js or anywhere in your pack
$(document).on('ajax:success', '.follow-btn', function(event){
let $el = $(this);
let method = this.dataset.method;
if (method === 'post') {
$el.text('Unfollow');
this.dataset.method = 'delete';
} else if (method === 'delete') {
$el.text('Follow');
this.dataset.method = 'post';
}
});
Why is this better than a js.erb template?
No server side involvement in updating the UI on the client. No spagetti-code views.
JavaScript is minified, not generated by ERB and easy to debug/reason about.
It can be changed to use optimistic create/delete to give instant feedback
Related
I am building a rails app that creates a like(create) or unlike(destroy), on a link click with a remote: true ajax request
The Post goes through and the transaction is committed but the the js response is not going through and I receive a Error in the server console
No template found for ForumThreads::ForumPosts::LikesController#create, head :no_content
the view structure is
forum_threds/show.html.haml
....
= render #forum_thread.forum_posts
....
to render a view of every post that is in the thread
than
forum_posts/_forum_post.html.haml
....
%div{id: "fourm_post_#{forum_post.id}" }
= render partial: "forum_posts/likes", locals: { post: forum_post }
....
which is rendering
forum_posts/_likes.html.haml
- if user_signed_in? && current_user.likes?(post)
= link_to "UnLike", forum_post_likes_path(post), method: :delete,
remote: true
- else
= link_to "Like", forum_post_likes_path(post), method: :post, remote:
true
and my controller is
class ForumThreads::ForumPosts::LikesController < ApplicationController
before_action :authenticate_user!
before_action :set_forum_post
before_action :set_forum_thread
def create
#forum_post.likes.where(user_id: current_user.id).first_or_create
respond_to do |format|
format.js
format.html { redirect_to #forum_thread}
end
end
def destroy
#forum_post.likes.where(user_id: current_user.id).destroy_all
respond_to do |format|
format.js
format.html { redirect_to #forum_thread}
end
end
private
def set_forum_thread
#forum_thread = ForumThread.find(#forum_post.forum_thread_id)
end
def set_forum_post
#forum_post = ForumPost.find(params[:forum_post_id])
end
end
With remote: false this works as expected with the page reload but when i put remote: true I receive the no template error
my file structure for the views
forum_threads/
show.html.haml
forum_posts/
show.html.haml
_likes.html.haml
likes/
create.js.erb
destroy.js.erb
and the create.js.erb and destroy.js.erb
$("#forum_post_<%= forum_post.id %>").html(<%= j render
'forum_posts/likes' %>);
but i know that this file isn't even being called
is there a way from the format.js that i may be able to call the file i need directly? or something?
I have implemented follow/unfollow functionality and would like to add AJAX call to it, but I am stuck.
My partial _follow_button.html.erb for follow/unfollow which is rendered on Users->index, looks like:
<% if current_user.id != user.id %>
<% if !current_user.following?(user) %>
<%= form_for(current_user.active_relationships.build, remote: true) do |f| %>
<div><%= hidden_field_tag :followed_id, user.id %></div>
<span class="follow"><%= f.submit "Follow User", class: "btn btn-primary btn-sm" %></span>
<% end %>
<% else %>
<%= form_for(current_user.active_relationships.find_by(followed_id: user.id),
html: { method: :delete }, remote: true) do |f| %>
<span class="unfollow"><%= f.submit "Unfollow User", class: "btn btn-secondary btn-sm" %></span>
<% end %>
<% end %>
<% end %>
Then my controller for relationships looks like:
class RelationshipsController < ApplicationController
respond_to :js, :json, :html
def create
user = User.find(params[:followed_id])
#follow = current_user.follow(user)
end
def destroy
user = Relationship.find(params[:id]).followed
#unfollow = current_user.unfollow(user)
end
end
My view on user profile looks like:
<div class="col-5" style="margin-left: -5px;">
<%= render '/components/follow_button', :user => User.find_by_username(params[:id]) %>
</div>
My routes.rb have the following routes defined:
resources :users do
member do
get :following, :followers
end
end
resources :relationships, only: [:create, :destroy]
My Views folder structure has subfolders Users and Relationships. Both of them have separate controllers, and I have tried adding simple alert function 'alert("Works");' to the create.js.erb in both of those subfolders to try and match them with the controller, but none don't seem to work. This is my first Rails project, and I do not quite understand what the issue could be. Any suggestions?
Calling the partial follow/unfollow
<% if current_user.id != user.id %>
<%= render partial: 'follow_links', locals: { user: user }
<% end %>
Partial follow_links.
<% show_follow_link = current_user.following?(user) ? 'hidden' : '' %>
<% show_unfollow_link = current_user.following?(user) ? '' : 'hidden' %>
<!-- links to follow/unfollow have data-attributes that include the path to make the ajax post and the user to follow, that is used to find the link to show after the ajax call. You should use the path to the controller that will create or destroy the relationship -->
<%= link_to 'Follow', '#', { class: 'follow-user btn-success #{show_follow_link}', "data-url": follow_user_path(user.id), "data-followee": user.id } %>
<%= link_to 'Unfollow', '#', { class: 'unfollow-user btn-danger #{show_unfollow_link}', "data-url": unfollow_user_path(user.id), "data-followee": user.id } %>
Javascript for the partial. Ajax post to follow/unfollow
$('.follow-user').on("click",function() {
follow_unfollow($(this), "follow")
});
$('.unfollow-user').on("click",function() {
follow_unfollow($(this), "unfollow")
});
function follow_unfollow(target, what_to_do)
url = target.attr('data-url')
followee = target.attr('data-followee')
if (what_to_do == "follow") {
other_button = $('.unfollow-user[data-followee="'+followee+'"]')
} else {
other_button = $('.follow-user[data-followee="'+followee+'"]')
}
$.ajax( {
url: url,
type: 'post',
success: function() {
// Hide this link
target.addClass('hidden');
// Show the other link
other_button.removeClass('hidden');
},
error: function(ret) {
alert(ret.responseJSON.error);
}
});
};
Changes in your controller.
class RelationshipsController < ApplicationController
def create
user = User.find(params[:followed_id])
#follow = current_user.follow(user)
respond_to do |format|
if #follow.valid?
format.html
format.json: { render json: #follow }
return
else
format.html
format.json: { render json: { :error => 'Follow failed', :status_code :not_found } }
end
end
end
def destroy
user = Relationship.find(params[:id]).followed
#unfollow = current_user.unfollow(user)
respond_to do |format|
if #unfollow.valid?
format.html
format.json: { render json: #unfollow }
else
format.html
format.json: { render json: { :error => 'Unfollow failed', :status_code :not_found } }
end
end
end
end
An advice
An advice, also regarding your last question: I would recommend - instead of posting questions about debugging code on StackOverflow - create a good debugging environment for yourself.
Byebug or Binding pry is a good place to start, but before you can use those properly you need to understand the code you are using. I would recommend reading Working with Javascript in depth! - it really helped me getting the hang of it and understanding the dataflow of Rails and ajax.
This would, i think, break the unbreakable Stackoverflow-loop, that i myself were tied to for a long time:
loop do
puts "Try code"
sleep 1000
puts "Arrhh! an error!"
sleep 1000
puts "Posting on Stackoverflow"
sleep 1000
puts "Waiting for answer"
sleep 1000
end
I hope you figure it out!
I have a simple inventory system application I've been developing for a class project. One of the requirements is to have some form of Javascript and AJAX doing something in the app. It doesn't have to be anything large or super complicated, but it does have to be there. What my group decided to do was render a popup that displays information about an item when you click on the 'show' link, as it was similar to an example the professor did in class and it was somewhat useful for our app as well. However I cannot get it to work, it just bypasses the ajax and javascript stuff and goes straight to the show.html.haml page. Here is my code:
index.html.haml
%p#notice= notice
%h1 Items
%table
%thead
%tr
%th Name
%th Description
%th Quality
%th Price
%th Location
%th Options
%tbody
- #items.each do |item|
%tr
%td= item.name
%td= item.description
%td
= item.quality
%br/
%br/
= item.quality_desc
%td= item.price
%td= item.location
%td{:colspan => "3"}
= link_to 'Show', item, class: "items"
= link_to 'Edit', edit_item_path(item)
= link_to 'Destroy', item, method: :delete, data: { confirm: 'Are you sure?' }
%br/
= link_to 'New Item', new_item_path
_item.html.haml
This is the information that the popup is supposed to display
%h1 Items
%h2
= item.name
, #{item.category}
%br/
- item.images.each do |image|
= image_tag(image.small.url)
%br
Price: $#{item.price}
%br/
Description: #{item.description}
%br/
Quality: #{item.quality},
\#{item.quality_desc}
%br/
Location: #{item.location}
%br/
%br/
%br/
= link_to 'Edit', edit_item_path(#item)
= link_to 'Close', '', id: 'closeLink'
items_controller.rb
class ItemsController < ApplicationController
before_action :set_item, only: [:show, :edit, :update, :destroy]
# GET /items
# GET /items.json
def index
#items = Item.all
end
# GET /items/1
# GET /items/1.json
def show
render(:partial => 'item', :object => #item) if request.xhr?
end
# GET /items/new
def new
#item = Item.new
end
# GET /items/1/edit
def edit
end
# POST /items
# POST /items.json
def create
#item = Item.new(item_params)
respond_to do |format|
if #item.save
format.html { redirect_to #item, notice: 'Item was successfully created.' }
format.json { render :show, status: :created, location: #item }
else
format.html { render :new }
format.json { render json: #item.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /items/1
# PATCH/PUT /items/1.json
def update
respond_to do |format|
if #item.update(item_params)
format.html { redirect_to #item, notice: 'Item was successfully updated.' }
format.json { render :show, status: :ok, location: #item }
else
format.html { render :edit }
format.json { render json: #item.errors, status: :unprocessable_entity }
end
end
end
# DELETE /items/1
# DELETE /items/1.json
def destroy
#item.destroy
respond_to do |format|
format.html { redirect_to items_url, notice: 'Item was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_item
#item = Item.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def item_params
params.fetch(:item, {}).permit(:name, :description, :quality, :quality_desc, :price, :location, :category, { images: [] })
end
end
items.js
var ItemPopup = {
setup: function() {
// add hidden 'div' to end of page to display popup:
var popupDiv = $('<div id="itemInfo"></div>');
popupDiv.hide().appendTo($('body'));
$(document).on('click', '#items a', ItemPopup.getItemInfo);
},
getItemInfo: function() {
$.ajax({type: 'GET',
url: $(this).attr('href'),
timeout: 5000,
success: ItemPopup.showItemInfo,
error: function(xhrObj, textStatus, exception) {alert('Error!'); }
//'success' and 'error' functions will be passed 3 args
});
return(false);
},
showItemInfo: function(data, requestStatus, xhrObject) {
//center a floater 1/2 as wide and 1/4 as tall as screen
var oneFourth = Math.ceil($(window).width() / 4);
$('#itemInfo').css({'left': oneFourth, 'width': 2*oneFourth, 'top': 250}).html(data).show();
//make the Close link in the hidden element work
$('#closeLink').click(ItemPopup.hideItemInfo);
return(false); //prevent default link action
},
hideItemInfo: function() {
$('#itemInfo').hide();
return(false);
}
};
$(ItemPopup.setup);
application.js
// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file. JavaScript code in this file should be added after the last require_* statement.
//
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require jquery
//= require jquery_ujs
// require turbolinks
// require_tree .
//= require items
application.html.haml
!!!
%html
%head
%meta{:content => "text/html; charset=UTF-8", "http-equiv" => "Content-Type"}/
%title InventoryManager
= csrf_meta_tags
// = stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload'
// = javascript_include_tag 'application', 'data-turbolinks-track': 'reload'
= stylesheet_link_tag 'application'
= javascript_include_tag "application"
%body
%nav.navbar.navbar-default
.container-fluid
/ Brand and toggle get grouped for better mobile display
.navbar-header
%button.navbar-toggle.collapsed{"aria-expanded" => "false", "data-target" => "#bs-example-navbar-collapse-1", "data-toggle" => "collapse", :type => "button"}
%span.sr-only Toggle navigation
%span.icon-bar
%span.icon-bar
%span.icon-bar
%a.navbar-brand{:href => "/default/index"} InventoryManager
/ Collect the nav links, forms, and other content for toggling
#bs-example-navbar-collapse-1.collapse.navbar-collapse
%ul.nav.navbar-nav
%li.active
%a{:href => "#"}
Items
%span.sr-only (current)
%ul.nav.navbar-nav.navbar-right
- if admin_signed_in?
%li= link_to "Logout", destroy_admin_session_path, :method => :delete
- elsif employee_signed_in?
%li= link_to "Logout", destroy_employee_session_path, :method => :delete
- else
%li
%a{:href => "/admins/sign_in"} Admin
%li
%a{:href => "/employees/sign_in"} Staff
/ /.navbar-collapse
/ /.container-fluid
= yield
If you need anymore of the code just ask. This is in Ruby on Rails 5
EDIT: So I fixed it by changing the selector in the event handler function so that it read '#items' and it grabbed the elements on my page with that id. However I got the code I was trying to use originally from a textbook, implying that what was there was supposed to work. Can someone explain to me why it didn't work initially?
EDIT2: Nevermind I figured it out.
So it turns out my trouble was this line right here:
$(document).on('click', '#items a', ItemPopup.getItemInfo);
I got this code from my class's textbook and modified it slightly to fit my application. As a result of this and a lack of knowledge of how the selectors worked, I thought this was selecting anchor tags with an id of 'items'. As it turns out, what it was actually doing is getting all the anchor tags inside an element with an id of 'items', in the case of the book, this particular element was a table, and the only links inside that table went to that applications show.html.haml page. That didn't quite work for my app since the index table has 3 different types of links on it, so I changed the line to read
$(document).on('click', '.items', ItemPopup.getItemInfo);
and changed the 'show' links on my index.html.haml to have a class of 'items'. This fixed my problem and it works perfectly now.
That being said if there is a solution to this sort of problem that is considered a better practice feel free to share it as an answer to this proble, as well, I'm all for learning something new.
I am uploading a file in my chat application, but on upload it is redirecting the page. I have tried in many ways to restrict it but i failed.
Please help me with your valuable response.
Attachment Model:
class Attachment < ApplicationRecord
belongs_to :user
belongs_to :chat
validates_presence_of :user_id , :chat_id
has_attached_file :attachment
validates_attachment_content_type :attachment, content_type: /.*/
end
Attachment Controller:
class AttachmentsController < ApplicationController
before_action :logged_in_user
layout false
def create
#chat = Chat.find(params[:chat_id])
#attachment = #chat.attachments.build(attachment_params)
#attachment.user_id = current_user.id
if #attachment.save
ActionCable.server.broadcast 'messages',
message: #attachment.attachment,
user: #attachment.user.name,
action: "attachment"
head :ok
end
end
private
def attachment_params
params.require(:post).permit(:attachment)
end
end
Attachment View:
<%= form_for #attachment , url: "/chats/#{#chat.id}/attachments", :remote => true, authenticity_token: true, html: { multipart: true } do |f| %>
<%= f.hidden_field :chat_id, value: #chat.id %>
<input type="file" name="post[attachment]" onchange="this.form.submit();return false;" id="message_attachment" type="file">
<% end %>
Javascript for updating on Front-end:(using Rails ActionCable)
App.messages = App.cable.subscriptions.create('MessagesChannel',{
received: function(data) {
$('#new-messages').removeClass('hidden');
if (data.action == "attachment") {
return $('#new-messages').append(this.renderAttachment(data));
}
},
renderAttachment: function(data) {
return data.message //"<li class='<%= self_or_other(data)%>'><div class='chatboxmessagecontent'><p>" + data.message + "</p>" + data.user + " • " + "</div></li>";
}
})
EDIT - 1
In Front End I am updating as
<% if #attachments.any? %>
<div id="messages">
<%= render partial: 'attachments/attachment', collection: #attachments %>
</div>
<div class="hidden" id="new-messages"></div>
<span id="istyping"></span>
<% else %>
<div class="hidden" id="new-messages"></div>
<% end %>
Attachment Parital
<li class="<%= self_or_other(attachment) %>">
<div class="chatboxmessagecontent">
<a href="<%= attachment.attachment.url %>" download>
<%= image_tag attachment.attachment.url, height: '64', width: '64' %>
</a><br/>
<time datetime="<%= attachment.created_at %>" title="<%= attachment
.created_at.strftime("%d %b %Y at %I:%M%p") %>">
<%= message_interlocutor(attachment).name %> • <%= attachment.created_at.strftime("%H:%M %p") %>
</time>
</div>
</li>
I suspect the reason you are getting redirected is because you are not specifying how to respond to different request formats. I would need to see your server log for somethings along the lines of:
Started GET "/chats/#{#chat.id}/attachments" for 127.0.0.1 at 2016-09-13 15:38:23 +0900
Processing by Rails::AttachmentsController#create as HTML #<= this
You must specify how to respond to different request formats such as HTML or JS. Your form is using the remote: true param so it should be a JS request(ajax).
def create
respond_to do |format|
format.js do
#chat = Chat.find(params[:chat_id])
#attachment = #chat.attachments.build(attachment_params)
#attachment.user_id = current_user.id
if #attachment.save
broadcast_attachment(#attachment)
return head :no_content
end
end
end
end
def broadcast_attachment(attachment)
ActionCable.server.broadcast 'messages', message: attachment.attachment,
user: attachment.user.name,
action: 'attachment'
end
Let me know if the problem persists.
EDIT#1
When using the respond_to method, you must also specify the HTML format for some reason.
respond_to do |format|
format.js do
...
end
format.html { ... }
end
If you just need the default behavior for HTML, you can simply use:
format.html
On removing of head: ok in Controller File. It is not redirecting.
Cheers.
I'm trying to implement Dropzone.js to my Rails 4 app. I have the little box going but nothing else seems to be working. While I know it may be a piece of cake for someone on here, I've been spending about 2 days trying to figure this out.
Here's what I have and done so far:
Added:
gem 'dropzonejs-rails'
Added to application.js:
//= require dropzone
Application.scss
*= require dropzone/dropzone
Here is the form that I want Dropzone.JS on:
What I currently have so far on my form page:
The box appears, but neither drag and drop nor any other function works...
Additional information: I'm using Paperclip and I want to be able to upload and save multiple images to each post I'm having.
I'm not sure if this is necessary but
Post.rb:
post_controller.js
class PostsController < ApplicationController
before_action :find_posts, only: [:show, :edit, :update, :destroy, :upvote, :downvote]
before_action :authenticate_user!, except: [:index, :show, :home]
def home
end
def index
if params[:category].blank?
#posts = Post.all.order("created_at DESC")
else
#category_id = Category.find_by(name: params[:category]).id
#posts = Post.where(category_id: #category_id).order("created_at DESC")
end
end
def show
#inquiries = Inquiry.where(post_id: #post).order("created_at DESC")
#random_post = Post.where.not(id: #post).order("RANDOM()").first
end
def new
#post = current_user.posts.build
end
def create
#post = current_user.posts.build(post_params)
if #post.save
redirect_to #post
else
render 'new'
end
end
def edit
end
def update
if #post.update(post_params)
redirect_to #post
else
render 'edit'
end
end
def destroy
#post.destroy
redirect_to root_path
end
def upvote
#post.upvote_by current_user
redirect_to #post
end
def downvote
#post.downvote_by current_user
redirect_to #post
end
private
def find_posts
#post = Post.find(params[:id])
end
def post_params
params.require(:post).permit(:title, :price, :description, :location, :category_name, :contact_number, :image)
end
end
What I need help with:
Implementing Dropzone.JS so I can upload multiple images to my post _form and have it appear on my post show page.
Thank you in advance!
UPDATE:
This is what appears:
Based on the DropzoneJS documentation you should put the class dropzone on form element instead of the file upload element. After this the DropzoneJS finds all the file inputs and changes them inside the form.
So change the form generation line to
= simple_form_for #Post, html: { multipart: true } do |f|
to
= simple_form_for #Post, html: { multipart: true, class: 'dropzone' } do |f|
#Loi Huynh : hi Loi! You can see examples at this site : http://sudharti.github.io/articles/dropzone-rails/
I having problems updating nested form ... if you want us to discuss this issue.
this my code :
<%= form_for(#product, html: {class: "dropzone", multipart: true}) do |f| %>
<div id="previews" class="dropzone-previews">
<div class="dz-default dz-message" align="center">
<span class="btn btn-primary">Click vào đây để thêm Ảnh</span>
</div>
</div>
<div class="col-md-4 col-md-offset-4" align="center">
<br/>
<div class="actions">
<%= f.submit "Hoàn Tất", id: "submit-all", class: "btn btn-primary btn-sm" %>
<%= link_to 'Quay về', products_path, class: "btn btn-primary btn-sm" %>
</div>
</div>
and my products_controllers :
def create
#product = Product.new(product_params)
respond_to do |format|
if #product.save
format.html { redirect_to products_url, notice: 'Tạo mới thành công.!.' }
format.json { render :show, status: :created, location: #product }
else
render json: { error: #post.errors.full_messages.join(',')}, :status => 400
end
end
end
and my upload.js
$(".dropzone").dropzone({
autoProcessQueue : false,
paramName: "product[photos_attributes][][image]",
previewsContainer: "#previews",
init: function() {
var myDropzone = this;
this.element.querySelector("#submit-all").addEventListener("click", function(e) {
e.preventDefault();
e.stopPropagation();
myDropzone.processQueue();
});
},
});