I'm really new at working with AJAX. I'm trying to make a little status update type thing, similar to facebook or twitter. You post a status and it adds it to the list below you, and clears out the edit box.
The post is being added to the database just fine. The problem is the list of recent status messages is not being redrawn. I'm getting an error, ArgumentError (wrong number of arguments (2 for 1)).
I have tried to rewrite the js.erb several ways and it always has the error. Some assistance would be appreciated.
The Controller posts#create
def create
#post = Post.new(post_params)
#post.user_id = current_user.id
respond_to do |format|
if #post.save
#posts = Post.all
format.html { redirect_to #post, notice: 'Post was successfully created.' }
format.js render ##posts } # { render :show, status: :created, location: #post }
else
format.html { render :new }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
The Partial _inline.html.erb /posts/inline
<div class="large-12 columns" id="inline_posts">
<% #posts.each do |post| %>
<div class="row">
<div class="large-10 columns left"><%= post.content %></div>
<div class="large-2 columns right"><%= link_to 'Remove', post, method: :delete, data: { confirm: 'Are you sure?' }, class: 'tiny button' %></div>
</div>
<% end %>
</div>
The Javascript create.js.erb
$("#inline_posts").html("<%= escape_javascript("render partial: 'posts/inline', posts: #posts ") %>")
Looks like if i change
format.js render
to
format.js
it works fine.
Sorry for the bother
Related
I've added a realtime chat to my rails application using only vanilla javascript. I've included it below. I'm just wondering, are there any security issues just looking at the code I've provided? I'm just not sure whether there's any issues with AJAX injections or any unknown unknowns I need to worry about. I didn't add ActionCable mainly because I don't need all of its functionality. Thanks for your help! :)
A chat has many private messages between 2 users. Users have many messages. I've added policies using pundit so only authorized users can access chats. And I'm using devise so only logged in users can access chats. Every model uses UUID.
chats/show.html.erb
<% if #messages %>
<div id="messages">
<%= render #messages %>
</div>
<% end %>
<%= form_with(model: [#chat, Message.new], local: false, html: { id: "message-form" }) do |form| %>
<div class="field">
<%= form.text_area :content, placeholder: "Send a message" %>
</div>
<div class="actions">
<%= form.submit %>
</div>
<% end %>
messages/_message.html.erb
<%= message.user.name %>
<%= message.content %>
messages/create.js.erb
var messages = document.querySelector("#messages");
messages.insertAdjacentHTML("beforeend", "<%= j render(#message) %>");
document.getElementById("message-form").reset();
controllers/messages_controller.rb
def create
#chat = Chat.find(params[:chat_id])
#message = #chat.messages.build(message_params)
#message.user = current_user
authorize #message
respond_to do |format|
if #message.save
format.html { redirect_to #chat, notice: 'Message was successfully created.' }
format.js
format.json { render :show, status: :created, location: #chat }
else
format.html { redirect_to #chat, alert: 'Message not created.' }
format.json { render json: #message.errors, status: :unprocessable_entity }
end
end
end
controllers/chats_controller.rb
def show
#listing = Listing.find(params[:listing_id])
#chats = #listing.chats
#chat = Chat.find(params[:id])
if #chat.messages
#messages = #chat.messages
end
end
I am using ajax-rails to render my form and validations stopped working. When I click to submit empty for which should validate, validation does not take effect and backend log shows it posted empty form. If I don't use ajax it works fine. I don't know what I am missing.
model
class ClockEntry < ApplicationRecord
belongs_to :user
validates :purpose, presence: true # I validated the attribute
end
index.html.erb
<div class="container" id="new-clock-entry">
<%= link_to 'New Clock Entry', new_clock_entry_path, remote: true, class: 'btn btn-primary btn-sm' %>
</div>
_form.html.erb
<%= simple_form_for clock_entry, remote: true do |f| %>
<%= f.error_notification %>
<%= f.error_notification message: f.object.errors[:base].to_sentence if f.object.errors[:base].present? %>
<div class="form-inputs">
<%= f.input :purpose %>
</div>
<div class="form-actions">
<%= f.button :submit, class: 'btn btn-primary btn-block btn-lg' %>
</div>
<% end %>
new.html.erb
<h1>New Clock Entry</h1>
<%= render 'form', clock_entry: #clock_entry %>
<%= link_to 'Back', clock_entries_path %>
new.js.erb
$('#new-clock-entry a').hide().parent().append("<%= j render 'form', clock_entry: #clock_entry %>")
create.js.erb
$('#new-clock-entry form').remove();
$('#new-clock-entry a').show();
$('table#clock-entry tbody').append("<%= j render #clock_entry %>");
controller
def new
#clock_entry = ClockEntry.new
end
def create
#clock_entry = current_user.clock_entries.new(clock_entry_params)
#clock_entry.set_time_in
respond_to do |format|
if #clock_entry.save
format.js { redirect_to root_path, notice: 'Clock entry was successfully created.' }
format.html { redirect_to #clock_entry, notice: 'Clock entry was successfully created.' }
format.json { render :show, status: :created, location: #clock_entry }
else
format.html { render :new }
format.json { render json: #clock_entry.errors, status: :unprocessable_entity }
end
end
end
#arieljuod in the comments section was very instrumental to me solving this. As he mentioned firstly, I am not asking my format to respond to js under the else condition of the create method. So this is what I did:
controller create action
Add the line below to the else condition of the create action:
format.js { render :new }
So my controller action becomes:
def create
#clock_entry = current_user.clock_entries.new(clock_entry_params)
#clock_entry.set_time_in
respond_to do |format|
if #clock_entry.save
format.html { redirect_to #clock_entry, notice: 'Clock entry was successfully created.' }
format.js { redirect_to root_path, notice: 'Clock entry was successfully created.' }
format.json { render :show, status: :created, location: #clock_entry }
else
format.js { render :new } # Added this...
format.html { render :new }
format.json { render json: #clock_entry.errors, status: :unprocessable_entity }
end
end
end
new.js.erb file
Then in the new.js.erb file, upon rendering the :new form, you need to remove or hide what is already there and append a new form that has the error message. So I had to remove the whole form by supplying the form tag to be hidden in my new.js.erb. So I add this line below to my new.js.erb file:
$('#new-clock-entry form').hide().parent().append("<%= j render 'form', clock_entry: #clock_entry %>")
So new new.js.erb file now becomes:
$('#new-clock-entry a').hide().parent().append("<%= j render 'form', clock_entry: #clock_entry %>")
$('#new-clock-entry form').hide().parent().append("<%= j render 'form', clock_entry: #clock_entry %>")
I think this should be handy to anyone who runs into the same problem.
I keep receving an error on my home page saying
'undefined method `company' for nil:NilClass'
for the first line of the following code displayed below. I am not really sure on how to fix this. I have two Controllers for both companies and customers because I am creating a two-sided marketplace.
When the user clicks the logo at the top instead of being redirected to the welcome page, the login page is being rendered since the home page is the root_path but I am using devise for before_action authenticate is being used.
<% if((current_user.company) || (current_user.customer)) %>
<%= render 'pages/welcome' %>
<% else %>
<% if current_user.is_company %>
<%= render 'companies/form', company: #company%>
<% else %>
Here is the home.html.erb file with the code which is the root_path
<% if((current_user.company) || (current_user.customer)) %>
<%= render 'pages/welcome' %>
<% else %>
<% if current_user.is_company %>
<%= render 'companies/form', company: #company%>
<% else %>
<%= render 'customers/form', customer: #customer%>
<% end %>
<% end %>
Here is my companiesController
class CompaniesController < ApplicationController
before_action :set_company, only: [:show, :edit, :update, :destroy]
def index
#companies = Company.all
end
# GET /companies/1
# GET /companies/1.json
def show
#company = Company.find(params[:company_id])
end
# GET /companies/new
def new
#company = Company.new
end
# GET /companies/1/edit
def edit
end
# POST /companies
# POST /companies.json
def create
#company = Company.new(company_params)
respond_to do |format|
if #company.save
format.html { redirect_to #company, notice: 'Company was successfully created.' }
format.json { render :show, status: :created, location: #company }
else
format.html { render :new }
format.json { render json: #company.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /companies/1
# PATCH/PUT /companies/1.json
def update
respond_to do |format|
if #company.update(company_params)
format.html { redirect_to #company, notice: 'Company was successfully updated.' }
format.json { render :show, status: :ok, location: #company }
else
format.html { render :edit }
format.json { render json: #company.errors, status: :unprocessable_entity }
end
end
end
# DELETE /companies/1
# DELETE /companies/1.json
def destroy
#company.destroy
respond_to do |format|
format.html { redirect_to companies_url, notice: 'Company was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_company
#company = Company.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the
white list through.
def company_params
params.require(:company).permit(:username, :phone, :website, :street, :city, :state, :country, :user_id)
end
end
it just says that the current_user is nil, you need to make sure that the user is logged in to use current_user.company
The log is giving you details as to why the company is returning a nil. The company requires an object in it for the page to load properly. But that is not so because no user is logged in for the company to have an object to return.
<% if((current_user.company) || (current_user.customer)) %> <%=
render 'pages/welcome' %> <% else %>
<% if current_user.is_company %> <%= render 'companies/form',
company: #company%> <% else %>
is returning a nil because no user is logged in.
You can first check if there is a user logged in and then render
something before this to prevent the error page
<% if(current_user) <% if((current_user.company) ||
(current_user.customer)) %>
<%= render 'pages/welcome' %> <% else %>
<% if current_user.is_company %>
<%= render 'companies/form', company: #company%> <% end %> <% else %> render something here <% end %>
Or simply log in to make sure this does not return a nil. But the first fix is the most ideal.
I'm currently trying to use the nested form with cocoon, is awesome !! But I'm facing to an interrogation and I don't know which way I should take.
Relations :
Ranch have Cows
Ranch have Productions
Production have nested form Iproductions
What I'm trying to do now is implement my iteration |c| into each of my iproductions:cow_id elements
My code:
(My_form production)=
<%- #cows.each do |c| %>
<div class="row">
<div class="col-md-12">
<div id="Order">
<%= f.simple_fields_for :iproductions do |ip| %>
<%= render 'iproductions_fields', f: ip, cow: c %>
<%end%>
<div class="Order_links">
<%= link_to_add_association c.name, f, :iproductions, cow: c, class: "btn btn-default" %>
</div>
</div>
</div>
</div>
(My iproductions_fields)=
<div class="form-inline clearfix">
<div class="nested-fields">
<%= f.input :cow_id, :input_html => { :cow_id => :cow } %>
<%= f.input :quantity, input_html: {class: "form-input form-control"} %>
<%= link_to_remove_association "Supprimer", f, class: "form-button btn btn-default" %>
</div>
</div>
(My productions_controllers)=
class ProductionsController < ApplicationController
before_action :authenticate_user!
skip_before_action :configure_sign_up_params
before_action :set_ranch
before_action :set_production, except: [:create, :new, :show]
before_action :set_production2, only: [:show]
# GET /productions
# GET /productions.json
def index
#productions = Production.all
end
# GET /productions/1
# GET /productions/1.json
def show
#iproductions = Iproduction.where(id: params[:production_id])
end
# GET /productions/new
def new
#production = #ranch.productions.build
#cows = #ranch.cows
end
# GET /productions/1/edit
def edit
#cows = #ranch.cows
end
# POST /productions
# POST /productions.json
def create
#production = #ranch.productions.create(production_params)
#production.update(date: Date.today)
#cows = #ranch.cows
respond_to do |format|
if #production.save
format.html { redirect_to ranch_production_path(#production.ranch_id, #production), notice: 'Production was successfully created.' }
format.json { render :show, status: :created, location: #production }
else
format.html { render :new }
format.json { render json: #production.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /productions/1
# PATCH/PUT /productions/1.json
def update
respond_to do |format|
if #production.update(production_params)
format.html { redirect_to ranch_production_path(#production.ranch_id, #production), notice: 'Production was successfully updated.' }
format.json { render :show, status: :ok, location: #production }
else
format.html { render :edit }
format.json { render json: #production.errors, status: :unprocessable_entity }
end
end
end
# DELETE /productions/1
# DELETE /productions/1.json
def destroy
#production.destroy
respond_to do |format|
format.html { redirect_to ranch_productions_path(#production.ranch_id), notice: 'Production was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_ranch
#ranch = Ranch.find(params[:ranch_id])
end
def set_production2
#production = Production.find_by(id: params[:id])
end
def set_production
#production = #ranch.productions.find_by(id: params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def production_params
params.require(:production).permit(:name, :ranch_id, :created_at, :date, iproductions_attributes: [:id, :date, :cow_id, :quantity, :_destroy])
end
end
My real view , so I would like to Assign each iproduction with the button which generate the iproductions_fields
So if you have any idea of which way I can try to achieve this goal, you're welcome,
Thanks in advance
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();
});
},
});