Ajax doesn't work with Rails3.2 - ruby-on-rails

I want Follow button that changes to Un-Follow when its clicked.
But when it submits form, it doesn't do any at all.
Why?
My codes are like these
-----Action(users_controller.rb)-----
def set_follow
friend = User.find_by_username(params[:username])
if f = Friendship.find(:first, :conditions => { :user_id => current_user.id, :friend_id => friend.id})
f.destroy
flash[:notice] = "Now added to follow list"
respond_to do |format|
format.html { redirect_to set_follow }
format.js
end
#redirect_to :back
else
Friendship.create(:user_id => current_user.id, :friend_id => friend.id)
flash[:error] = "Now deleted from follow list"
respond_to do |format|
format.html { redirect_to set_follow }
format.js
end
#redirect_to :back
end
end
-----Form(users/index.html.erb)-----
<div id="follow_status">
<% if user_signed_in? && current_user.friends.find_by_id(user.id) %>
<%= link_to sanitize('<i class="icon-remove icon-white"></i> ') + 'Un-Follow', follow_user_path(user.username), :class => 'btn', remote: true %>
<% elsif current_user != user %>
<%= link_to sanitize('<i class="icon-ok icon-white"></i> ') + 'Follow', follow_user_path(user.username), :class => 'btn btn-primary', remote: true %>
<% end %>
</div>
-----JS View(set_follow.js.erb)-----
$("#follow_status").html("<%= escape_javascript(render f) %>");

Bit of a different method but I would just do this with JQuery
$('.btn').click( function() {
if( $('.btn').html() == 'Follow') {
$('.btn').html('Unfollow');
}
else if( $('.btn').html() == 'Unfollow') {
$('.btn').html('Follow');
}
});
​
This is just a bit of an example how you could do it. You would probably want to use a more specific chain of classes in the jquery

Related

Rails passing params in link_to how to make it secure

I am trying to create a like and dislike function inside rails for that I am using lin_to helper to pass params but there is an issue when ever someone tries to copy paste the links it updated the database . I am using ajax to make this function work here is the code for my method .
Controller code:
class FeedLikesController < ApplicationController
before_action :authenticate_user! ,only: [:create, :destroy]
before_action :get_feed ,only: [:create, :destroy]
def index
#fees = FeedLike.all
respond_to do |format|
format.html
format.js
end
end
def update
#feed_likes = FeedLike.find_or_create_by(feed_like_params)
respond_to do |format|
if #feed_likes.save
format.html { redirect_to root_url, notice: 'Like ' }
end
end
end
def create
#feed_like_counter = Feed.find(params[:feed_id])
#feed_likes = FeedLike.find_or_create_by(:feed_id => params[:feed_id],:user_id =>params[:user_id])
#f = #feed_like_counter.like_count
#feed_like_counter.like_count = #f+1
#feed_like_counter.save
respond_to do |format|
if #feed_likes.save
format.html { redirect_to root_url, notice: 'Like ' }
format.js
end
end
end
def delete
end
def destroy
#feed_like_counter = Feed.find(params[:feed_id])
#feed_likes = FeedLike.where(feed_like_params)
#f = #feed_like_counter.like_count
#feed_like_counter.like_count = #f-1
#feed_like_counter.save
respond_to do |format|
if #feed_likes.destroy_all
format.html { redirect_to root_url, notice: 'Unlike ' }
format.js
end
end
end
def feed_like_params
params.permit(:user_id, :feed_id)
#params[:market_place]
end
def get_feed
#feed = Feed.find(params[:feed_id])
end
end
And in views my link is like this:
<div class="feed-like-<%= #feed %> " >
<%= link_to "like",{ :action => 'create', :controller => 'feed_likes', :feed_id => #feed, :user_id => current_user.id, :remote => true }, method: :post,class: "btn btn-primary" %>
</div>
And dislike link is like this:
<div class="feed-like-<%= #feed %> " >
<%= link_to "Dislike",{ :action => 'destroy', :controller => 'feed_likes', :feed_id => #feed, :user_id => current_user.id, :remote => true }, class: "btn btn-primary" %>
</div>
And my routes is like :
get "/feed_likes/:feed_id/feed_likes/:user_id" => "feed_likes#destroy"
post "/feed_likes/:feed_id/feed_likes/:user_id" => "feed_likes#create"
Here the issue is whenever someone wants to like the feed when I passes the url direclty it updated the database how can I restrict this only when user click the button only then it update the database not by url :
There is another issue with this I am using ajax onclick event it updated the database but when I click the like button fast it update the databse 2 or 3 times before the dislike partial appear . Is there any way I can use this .
I find a solution for this question it was very easy I was trying to generate the routes not in rails way so I did some changes . First I added
resources :feed_likes
and then replace the links like this :
<%= link_to "Dislike", feed_like_path(:feed_id => #feed, :user_id => current_user.id ), :confirm => 'Are you sure?',:remote => true, :method => :delete,data: { disable_with: "Processsing..." }, class: "btn btn-primary" %>
<%= link_to "like", feed_likes_path(:feed_id => #feed, :user_id => current_user.id ), :confirm => 'Are you sure?',:remote => true, :method => :post, data: { disable_with: "Processsing..." }, class: "btn btn-primary" %>

Model Validation Messages Rails 4 form errors not showing up

I have a form which allows a user to invite multiple people via adding emails in a comma separated list. In my "Participant" model, I have a call to validate the uniqueness of the email entered (scoped by "project_id"). In the model validation, it gives a place to explain the error (message), but I can't get that error to show up on my form if the validation fails.
If a user enters the email of a person that has already been added, how can I get the errors message to render?
participant.rb
class Participant < ActiveRecord::Base
validates :email, uniqueness: {case_sensitive: false, scope: :project_id, message: "Looks like you\'ve already added this person."}
end
participant_controller.rb
def new_participant
#new_participants = Participant.new
#participants = Participant.where(project_id: #project.id).includes(:user)
#template = Template.find(#project.template_id)
#address = Address.where(project_id: #project.id).first
#food = ProjectRestriction.where(project_id: #project.id)
end
def add_participant
#added_by = User.find(current_user.id)
#new_participants = params[:new_participants][:email].split(/,\s*/)
#new_participants.each do |t|
newpart = Participant.new(:email => t, :project_id => #project.id, :level => 4,
:participant_cat_id => 2, :last_updated_by => current_user.id, :added_by => current_user.id, :status => 'unseen')
respond_to do |format|
if newpart.save
ProjectMailer.notify_recipient(newpart, #project, #added_by, #participant_invite ).deliver_later
self.response_body = nil
redirect_to participants_path(p: #project.id, w: 'recipient')
else
format.html { redirect_to new_participant_path(p: #project.id)}
format.json { render json: #new_participants.errors, status: :unprocessable_entity }
end
end
end
end
form
<%= form_for :new_participants, url: add_participant_path( :p => #project.id), html: { :multipart => true, :class=> "form-horizontal", id: "basicForm" } do |f| %>
<% if #new_participants.errors.any? %>
<h2>OOPS!</h2>
<ul>
<% #new_participants.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul></div>
<% end %>
<div class="form-group ">
<label class="form-label dk-aqua"> Email: <span class="asterisk">*</span></label>
<%= f.text_field :email, :autofocus => true, :required => true, :maxlength => 55, :placeholder => 'Email(s)', :class => 'form-control' %>
</div>
<%= f.submit 'INVITE', :class => 'btn btn-aqua btn-lg btn-block',
:style => 'margin-bottom:-5px' %>
<% end %>
Your main issues are:
you are creating a respond block for each email in the request. 1 request = 1 response.
The objects in stored in memory in #new_participants are not actually saved.
In your views your are treating #new_participants as if it where a single resource.
Pay attention to pluralization when naming routes, variables and actions.
def add_participants
#added_by = User.find(current_user.id)
#new_participants = params[:new_participants][:email].split(/,\s*/)
#new_participants.map do |email|
newpart = Participant.new(
:email => email,
:project_id => #project.id,
:level => 4,
:participant_cat_id => 2,
:last_updated_by => current_user.id,
:added_by => current_user.id,
:status => 'unseen'
)
if newpart.save
ProjectMailer.notify_recipient(newpart, #project, #added_by, #participant_invite ).deliver_later
end
new_part
end
#invalid = #new_participants.reject(&:valid?)
if #invalid.any?
respond_to do |format|
format.html { redirect_to new_participant_path(p: #project.id)}
format.json { render json: #new_participants.map(&:errors), status: :unprocessable_entity }
end
else
respond_to do |format|
redirect_to participants_path(p: #project.id, w: 'recipient')
end
end
end
<ul>
<% #new_participants.each |p| %>
<% p.errors.messages.each do |msg| %>
<li><%= msg %></li>
<% end if p.errors.any? %>
<% end %>
</ul>

Rails JS respond to create action fail

I'm having trouble getting the current page to reload, after posting a remote form in Rails 4, to create join object in my db. It works fine for another model association in my app, but not here....
View Form:
select from dropdown which collection to assign to:
<% unless current_user == nil %>
<div class="btn-group pull-right">
<a class="btn dropdown-toggle" data-toggle="dropdown" href="#">
Collect
<span class="caret"></span>
</a>
<ul class="dropdown-menu">
<% current_user.collections.each do |collection| %>
<% unless CollectionPiece.where(:collection_id => collection.id, :piece_id => #piece.id).exists? %>
<li><%= link_to raw("<i class='glyphicon glyphicon-plus'></i> #{collection.title}"), collection_pieces_path(:collection_piece => {:piece_id => #piece.id, :collection_id => collection.id}), :remote => true, class: "", :method => :post %></li>
<% end %>
<% end %>
<li><%= link_to raw("<i class='glyphicon glyphicon-th-large'></i> New Collection"), new_collection_path, :class => "" %></li>
</ul>
</div>
<% end %>
Collection Piece controller:
class CollectionPiecesController < ApplicationController
after_action :collection_email, only: :create
def create
#collection_piece = CollectionPiece.create(collection_piece_params)
respond_to do |format|
if #collection_piece.save
format.html { redirect_to :back, notice: 'Collection was successfully created.' }
else
format.html { redirect_to :back, notice: 'Collection was not successfully created.' }
end
end
end
def destroy
#collection_piece = CollectionPiece.where(collection_piece_params)
respond_to do |format|
if #collection_piece.first.destroy
format.js { redirect_to :back, notice: 'Collection was successfully destroyed.' }
else
format.js { redirect_to :back, notice: 'Collection was not successfully destroyed.' }
end
end
end
def collection_email
#profile = current_user.profile
#piece = Piece.find(params[:collection_piece][:piece_id])
#collection = Collection.find(collection_piece_params[:collection_id])
UserMailer.collection_email(#profile.user, #piece, #collection).deliver
end
private
# Never trust parameters from the scary internet, only allow the white list through.
def collection_piece_params
params.require(:collection_piece).permit(:piece_id, :collection_id)
end
end
create.js.erb:
console.log("why you no work?");
location.reload();
Hope you can help, let me know if you need more info?

Rails: return only json

In my app there is a list of items which you can upvote. I want to make these votes with AJAX calls.
This is the view:
<ul class="list-groups">
<% #questions.each do |question| %>
<li class="list-group-item">
<%= link_to question.description, question_path(question) %>
<%= form_for(question, :url => url_for(:controller => 'vote', :action => 'vote'), method: :post, html: { class: 'form-inline' }) do |f| %>
<%= f.submit 'Up vote', class: "btn btn-default" %>
<%= f.hidden_field :id, :value => question.id %>
<% end %>
</li>
<% end %>
</ul>
And this the method that does it:
class VoteController < ApplicationController
respond_to :json
def vote
question_id = params[:question][:id]
user_id = current_user.id
vote = Vote.where(["question_id = :q", { q: question_id }]).where(["user_id = :u", { u: user_id }])
respond_to do |format|
if vote.nil?
#vote = Vote.new
#vote.question_id = question_id
#vote.user_id = user_id
#vote.save
format.html { render '/home/index' }
format.json { render :json => { :status => 'ok' } }
else
format.html { render '/home/index' }
format.json { render :json => { :status => 'failed', :msg => 'You already voted' } }
end
end
end
end
If I don't include this format.html { render '/home/index' } I am getting this error:
ActionController::UnknownFormat in VoteController#vote
But I don't want to render the page again, I am just loading the pieces of html that will change after the action with jQuery and ajax.
How can I respond only with the json?
Use respond_with instead of respond_to in your controller action.
respond_with do |format|
respond_to at the top of your controller is designed to work with respond_with in your controller action, whereas respond_to in your controller action ignores the respond_to that you've defined at the top of your controller.
Also make sure you are making a remote call, instead of a normall one if you want your request to go through AJAX.
<%= form_for(question, :url => url_for(:controller => 'vote', :action => 'vote'), method: :post, remote: true, html: { class: 'form-inline' }) do |f| %>
Note the remote: true part that is added as an argument to the form_for helper.
You need to include remote: true in form_for in order to make the call requests AJAX instead of HTML.
<%= form_for(question, :url => url_for(:controller => 'vote', :action => 'vote'), remote: true, method: :post, html: { class: 'form-inline' }) do |f| %>
Check out the Working with JavaScript in Rails documentation for more information.

Rails post delete functionality giving template error

I am trying to have a link to delete a certain reservation from the database. This is my solution but it keeps giving Template Error. It shouldn't render the view but it is.
def delete
#current = Reservations.find(params['reservations']['id'])
respond_to do |format|
if current_user
if #current.user_id == current_user.id
#current.destroy
format.html { redirect_to :back }
else
format.html { redirect_to root_path }
end
else
format.html { redirect_to root_path }
end
end
end
My routes file
post "reservations/delete", to: 'reservations#delete', as: 'delete_reservation'
My view that includes the delete link:
<%= form_for item, :url => {:controller => 'reservations', :action => 'delete'}, :method => 'post' do |f| %>
<%= f.hidden_field :id, :value => item.id %>
<%= f.submit "Delete", :class =>'btn btn-danger btn-small' %>
<% end %>

Resources