Using Ajax requests in rails - ruby-on-rails

Hi I want to build an app using Ajax. Whenever a user visits an other user page he can add him as a friend by clicking add friend link. This is my current code in users/show page
<% if current_user.friend?(current_user,#user) %>
<%= link_to "Unfriend", relation_path(#relation), user: #user, method: :delete, data: { confirm: 'Are you sure? This action cannot be undone' }, class: 'btn btn-default' %>
<% elsif #user != current_user %>
<%= link_to "Add Friend", friendships_path(:friend_id => user), :method => :post, class: 'btn btn-default' %>
<% end %>
My code in relations controller
def create
if params[:friend_id]
if Relation.where(user_id: current_user.id, friend_id: params[:friend_id]).present?
redirect_to user_path(params[:friend_id]), notice: "Already friends"
elsif current_user.id == params[:friend_id]
redirect_to user_path(params[:friend_id]), alert: "Invalid Request"
else
#relation = current_user.relations.new(friend_id: params[:friend_id], subject: Constants::Subject::MAKE)
if #relation.save
friend = User.find(params[:friend_id])
friend.relations.create!(friend_id: current_user.id, subject: Constants::Subject::MAKE)
redirect_to user_path(params[:friend_id]), notice: "Added as friend"
else
redirect_to user_path(params[:friend_id]), alert: "Could not add as friend"
end
end
else
redirect_to current_user, notice: "Invalid Request"
end
end
I am following this Ryan Bates rails casts. How can I make the link_to add friend Ajax request instead of html request. The current code is working fine. I want to add Ajax functionality for this. I have seen a lot of questions but I could not understand what exactly to be done. Please help.

Add remote: true to the link_to tag. There is more information in the guides abou rails and ajax. You will need a respond_to block to handle the response.
Start with adding remote: true and use the console to see the call being made and what the response is. Then you can figure out how to handle the response.
<%= link_to "Add Friend", friendships_path(:friend_id => user), :method => :post, remote: true, class: 'btn btn-default' %>

Please take a look:
Move your buttons into a partial
Render it inside a div with ID = "actions"
Update your controller response with format js
Add field create.js.erb which render your buttons by javascript
Render your flashes box by javascript by the same way (if needed)
your view_file.erb
<div id="actions">
<%= render "views/realtions/actions", relation: #relation, friend: #user %>
</div>
views/realtions/_actions.html.erb
<% if current_user.friend?(current_user, friend) %>
<%= link_to "Unfriend", relation_path(relation), user: friend, method: :delete, remote: true, data: { confirm: 'Are you sure? This action cannot be undone' }, class: 'btn btn-default' %>
<% elsif friend != current_user %>
<%= link_to "Add Friend", friendships_path(friend_id: friend.id), method: :post, remote: true, class: 'btn btn-default' %>
<% end %>
views/realtions/create.js.erb
<%- if #friend.present? %>
$("#actions").html("<%= j render 'views/realtions/actions', relation: #relation, friend: #friend %>")
<%- end %>
// render your flashes to DOM here!
controllers/relations_controller.rb
def create
if params[:friend_id]
#friend = User.find(params[:friend_id])
if Relation.where(user_id: current_user.id, friend_id: #friend.id).present?
flash[:notice] = "Already friends"
elsif current_user.id == params[:friend_id]
flash[:error] = "Invalid Request"
else
#relation = current_user.relations.new(friend_id: params[:friend_id], subject: Constants::Subject::MAKE)
if #relation.save
#friend.relations.create!(friend_id: current_user.id, subject: Constants::Subject::MAKE)
flash[:notice] = "Added as friend"
else
flash[:error] = "Could not add as friend"
end
end
else
flash[:notice] = "Invalid Request"
end
respond_to do |format|
format.js
end
end
Hope this help

Related

Rails ActiveAdmin: ActiveRecord::RecordNotFound in Admin::UsersController#show

I want to create button to change User status:string from inactive to active inside active admin show action. To do so I'm using collection_action with below code:
ActiveAdmin.register User do
permit_params :email, :password, :password_confirmation, :status
collection_action :update_status, method: :post do
user.update!(status: 'active')
redirect_to user_path, notice: 'User status updated'
end
Then I render custom partial _show.html.erb
<tr>
<td colspan='2'>
<% if #user.status == 'inactive' %>
<%= link_to 'Activate user', update_status_admin_users_path %>
<% end %>
</td>
Here is what ActiveAdmin generated dynamically by collection_action
bin/rails routes
update_status_admin_users POST /admin/users/update_status(.:format) admin/users#update_status
Instead of updating the data I'm getting an error:
ActiveRecord::RecordNotFound in Admin::UsersController#show
Couldn't find User with 'id'=update_status
Above error is because you are redirecting to user_path for which id parameter it require to redirect, and as you are using collection_action id parameter is missing.
If your intention is to update just one user, then use member_action instead of collection_action.
using resource
member_action : update_status, method: :put do
resource.update!(status: 'active')
redirect_to user_path, notice: 'User status updated'
end
with own finder
member_action : update_status, method: :put do
user = User.find(params[:id])
user.update!(status: 'active')
redirect_to user_path, notice: 'User status updated'
end
<td colspan='2'>
<% if #user.status == 'inactive' %>
<%= link_to 'Activate user', update_status_admin_user_path, method: :put %>
<% end %>
</td>

Rails: Favorite Model working but favorite/unfavorite links not working

I followed the steps from the first answer posted by Thomas here
I can go into Heroku Console and manually favorite phootos by users so the models are setup correctly and working but my favorite/unfavorite links are not working.
<p><strong>Picture:</strong></p>
<%= image_tag(#phooto.picture) %>
<%= link_to("< Previous", #phooto.previous) if #phooto.previous %>
<%= link_to("Next >", #phooto.next) if #phooto.next %>
<% if current_user %>
<%= link_to "favorite", favorite_phooto_path(#phooto, type: "favorite"), method: :put %>
<%= link_to "unfavorite", favorite_phooto_path(#phooto, type: "unfavorite"), method: :put %>
<% end %>
Heroku Log
Started PUT "/phootos/24/favorite?type=favorite"
Completed 500 Internal Server Error in 2ms (ActiveRecord: 0.6ms)
ActiveRecord::AssociationTypeMismatch (Phooto(#70057240967940) expected, got NilClass(#70057199933300)):
app/controllers/phootos_controller.rb:29:in `favorite
PhootosController
def show
#phooto = Phooto.find(params[:id])
end
def favorite
type = params[:type]
if type == "favorite"
**rb.29** current_user.favorites << #phooto
redirect_to :back, notice: 'You successfully favorited #{#phooto.name}'
elsif type == "unfavorite"
current_user.favorites.delete(#phooto)
redirect_to :back, notice: 'You successfully unfavorited #{#phooto.name}'
else
redirect_to :back, notice: 'Nothing happened.'
end
end
Phootos/show.html.erb
<p><strong>Picture:</strong></p>
<%= image_tag(#phooto.picture) %>
<%= link_to("< Previous", #phooto.previous) if #phooto.previous %>
<%= link_to("Next >", #phooto.next) if #phooto.next %>
<% if current_user %>
<%= link_to "favorite", favorite_phooto_path(#phooto, type: "favorite"), method: :put %>
<%= link_to "unfavorite", favorite_phooto_path(#phooto, type: "unfavorite"), method: :put %>
<% end %>
routes.rb
resources :users
resources :phootos
resources :phootos do
put :favorite, on: :member
end
Honestly, a better pattern for this will be to match the favorite route based on its HTTP verb:
#config/routes.rb
resources :users
resources :phootos do
match :favorite, on: :member, via: [:put, :delete]
end
This will do away with the type argument in your path (which is causing issues):
<% if current_user %>
<%= link_to "favorite", favorite_phooto_path(#phooto), method: :put %>
<%= link_to "unfavorite", favorite_phooto_path(#phooto), method: :delete %>
<% end %>
You'll have to change your controller to handle the requests & variable:
def favorite
#phooto = Phooto.find params[:id]
if request.put?
current_user.favorites << #phooto
redirect_to :back, notice: 'You successfully favorited #{#phooto.name}'
elsif request.delete?
current_user.favorites.delete(#phooto)
redirect_to :back, notice: 'You successfully unfavorited #{#phooto.name}'
else
redirect_to :back, notice: 'Nothing happened.'
end
end
Just add this line as your first line in your favorite method in PhootosController
#phooto = Phooto.find(params[:id])

Ruby on Rails Page not reloading on submit button click

I have an Approve button that changes status attribute of the Shop table record. When I click on it, it does change attribute, but it doesn't reload the page, so I have to reload page manually to see the result, which is very inconvenient. Looks like everything has to work, but page still not reloading.
My view has:
<%= form_for([:admin, #shop], remote: true, data: { confirm: "You sure?" }) do |fr| %>
<%= fr.hidden_field :status, :value => 2 %>
<%= fr.submit "Reject", class: "btn btn-large btn-danger" %>
<% end %>
And the controller:
def update
#shop = Shop.find(params[:id])
if #shop.update_attributes(shop_params)
flash[:success] = "Shop updated"
redirect_to([:admin, #shop])
else
render 'edit'
end
end
I would be grateful for any help, thank you!
You are using remote: true in form_for, which is making your form submission via AJAX.
You may need to add method: :put so that form hits action update instead of create.
So just try removing remote: true and add method: :put as follow and try submitting form again.
<%= form_for([:admin, #shop], method: :put, data: { confirm: "You sure?" }) do |fr| %>
<%= fr.hidden_field :status, :value => 2 %>
<%= fr.submit "Reject", class: "btn btn-large btn-danger" %>
<% end %>
maybe you are missing the respond_to do |format| calls or did you omitted them on the question?
should be like that:
def update
#shop = Shop.find(params[:id])
respond_to do |format|
if #shop.update(shop_params)
format.html { redirect_to [:admin, #shop], notice: "Shop updated"
else
format.html { render action: 'edit' }
end
end
end
hope that helps.

Update a record with a button in Rails?

I'm trying to update a record in my Rails app using a button. I have a User and I want to update its school_id value. I have a School view page where a User can click on a button to add that school's id to the User school_id field. I'm struggling with the implementation. Here's what I have so far:
User controller:
def add_school
#user = User.find(params[:user_id])
#user.update_attributes(:school_id)
respond_to do |format|
flash[:notice] = "School has been added!"
format.html { redirect_to :back }
format.js
end
Button on School show page:
<%= button_to "Add School", add_school_user_path, :method => "put" %>
I tried to do this a different way by just adding code to the update action in the User controller but I couldn't get that to work either:
def update
#user = User.find(params[:id])
if #user.update_attributes(params[:school_id])
flash[:notice] = "School has been added!"
redirect_to #user
end
if #user.update_attributes(params[:user])
flash[:notice] = "Successfully updated account and profile!"
end
end
What's the best way to pass the School's id into the User school_id column?
Thanks!!
EDIT 1: Routes
resources :users do
member do
get :following, :followers
put :add_school
end
Updated controller:
def add_school
#user = current_user
#school = School.find(params[:id])
#user.update_attributes(school_id: params[:school_id])
respond_to do |format|
flash[:notice] = "School has been added!"
redirect_to #user.school
end
end
Updated button link:
<%= button_to "Add School", add_school_user_path(#user, school_id: #school.id), :method => :put %>
Routing error:
No route matches {:action=>"add_school", :controller=>"users", :school_id=>1, :id=>nil}
You need a form for that instead of just abutton
<%= form_tag add_school_user_path(#user), method: put do -%>
<%= hidden_field_tag :school_id, #school.id -%>
<%= submit_tag 'Add school' -%>
<%- end -%>
you didn't provide the context code, maybe #user and #school are not the real variable names but you can get the idea from this
The provided answer is no longer entirely accurate. You can pass data and update a record with a button_to, so long as you aren't attempting to pass arbitrary data.
The button_to syntax would be something like this -- please note, this is my implementation of it, and it is not adjusted to your specific implementation as your controller would need additional adjustments from what you've specificed to accept certain params --:
<%= button_to "Mark Completed", todo_path(todo.id),
params: {:todo => { :id => todo.id, :completed => true, :user_id => current_user.id }},
method: :put, data: { confirm: "Mark this To-Do as being completed? This will hide it from view." } %>
You need to pass the whole hash into the call to .update_attributes.
Preferably, you will put school_id inside of user, so it will look like
# params[:user] = { school_id: 1 }
#user.update_attributes(params[:user])
Or you could code the school id manually
#user.update_attributes(school_id: params[:school_id])
Or, better yet, validate the association
#user.school = School.find(params[:school_id]
The path you would want is
user_add_school_path(#user, school_id: 1)
This is an old Q, but nevertheless for the sake of completeness. You do not necessarily need a form for a simple form-alike submission with a button/link. You can rely on jquery-ujs and data-params.
<%= link_to add_school_user_path(#user), class: "btn btn-xs btn-primary",
title: "Add school",
data: {remote: true, confirm: 'Are you sure?', method: 'put',
params: {user: {schoold_id: #school.id}}} do %>
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span>
Add school…
<% end %>
Note that you'd want to have school_params method in your controller akin to params.require(:user).permit(:school_id)

Rails: AJAX + destroy action in controller not working?

Hi I am currently making an app with users, albums, and photos. I managed to make the AJAX work for the create action when I upload pics, but I can't get AJAX to work for the delete. Instead, it redirects me to an empty show page for the pic. Can anyone give me some guidance?
photos controller:
def destroy
#user = User.find(params[:user_id])
#album = #user.albums.find(params[:album_id])
#photo = #album.photos.find(params[:id])
# #photo.destroy
flash[:success] = "Photo successfully deleted."
respond_to do |format|
if #photo.destroy
format.js
# format.json { render json: #photo, status: :created, location: #photo}
# redirect_to user_album_path(#user, #album)
end
end
end
destroy.js.erb (I'm supposed to have this right?)
$('.destroypicswrapper').remove(".<%= #photo.avatar.url %>");
_photodestroy.html.erb partial:
<div class="picthumb <%= photo.avatar.url %>">
<%= link_to image_tag(photo.avatar.url ? photo.avatar.url(:small) : #album.name), root_url %>
<br>
<%= link_to "Delete", user_album_photo_path(#user, #album, photo), :remote => true, method: :delete, data: { confirm: "Are you sure? "} %>
</div>
and finally the albums/edit.html.erb page where the delete is initially happening:
<% provide(:title, "Edit album") %>
<%= render 'form' %>
<div class="destroypicswrapper">
<% if #album.photos.any? %>
<%= render :partial => 'photodestroy', :collection => #album.photos, :as => :photo %>
<% end %>
</div>
I don't think you want to render the full url of an image as a class of a div. Also, your Jquery is wrong. Try something like this:
destroy.js.erb
$('.destroypicswrapper > #photo_<%= #photo.id %>').remove();
Adjust your _photodestroy.html.erb to:
<div class="picthumb" id="photo_<%= photo.id %>">

Resources