Ruby on rails: Button_to Check post result and update current page - ruby

In my UI, I have a table of items. Each row has a favorite button. I am using button to make a rails call to add the db association.
I've been looking into how to check the result of the post response in my button to call.
If it succeeds, I want to disable the favorite button on my page and if it doesn't I want to nothing. Is there a way to check the post response in my button to call and is there a way to stay on the page?
Heres a sample of what I have
<%= button_to create_favorite_path(res.id), class: "favorite-btn-#{res.id} btn btn-default" do%>
<i class="glyphicon glyphicon-star-empty"></i>
<% end %>

To stay on the page when you click the button, you need to add remote: true to your button call. This will make your button request an AJAX call by default.
Read more about the button_to helper here.
<%= button_to create_favorite_path(res.id), remote: true, class: "favorite-btn-#{res.id} btn btn-default" do%>
<i class="glyphicon glyphicon-star-empty"></i>
<% end %>
Then to see the response of this AJAX request, you'll need to write some javascript.
In your application.js or whatever javascript file you have on this page:
$(document).on('ajax:success', 'form', function(event, data, status, xhr) {
// do something with data or status
});
Read more about working with javascript in Rails here.

Related

how to pass data between views/pages in Ruby on rails?

I have a ruby on rails app. I have a view that lists hyperlinks as such, this view is also rendered via same controller/action . when user clicks hyperlinks displayed on this page they go to the same controller/action, with a different id parameter. I want to be able to tell in my controller/view how user gets to these pages, i.e. whether user clicked on one of these hyperlinks vs user came through a different source?
<div id='list'>
<a href='controller/action/1'> some link 1 </a>
<a href='controller/action/2'> some link 2 </a>
</div>
Best approach is to add an URL parameter to the links.
<div id='list'>
<a href='controller/action/1?via=from_view'> some link 1 </a>
<a href='controller/action/2?via=from_view'> some link 2 </a>
</div>
Edit
You can access this URL parameter in your controller with params. Simple example:
class MyController < ApplicationController
def show
#via = params[:via] || "external"
end
end
<% if #via == "from_view" %>
<p>Hello coming from the view!</p>
<% elsif #via == "external" %>
<p>Hello coming from external!</p>
<% end %>
<div id='list'>
<a href='controller/action/1?via=from_view'> some link 1 </a>
<a href='controller/action/2?via=from_view'> some link 2 </a>
</div>
You can easily pass URL parameters into Rails URL helper.
For example:
<%= link_to "Link Title", some_url_helper_path(:param1 => "value1", :param2 => "value2") %>
Then you will be able to pass the parameters from the view to the controller's action.
Where the user came from is part of the HTTP spec (the referrer header) and you can access that in your controller with request.referer - you can then check if that value matches the page you want to target.
If your controller has #origin = request.referer You can then use if #origin == 'http://example.com/page-1’ in your view to switch what is being rendered.
This way you don’t have to remember to decorate all of your links with the extra param; rely on the fact that the browser is automatically adding it to headers for you.
Also see:
How to get request referer path?
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referer

RAILS 4: Trying to get the current page to pass to render in an AJAX request

I have a fairly straight forward question.
On my site, within the header is a "invite a colleague" link to a modal that contains a form:
<%= simple_form_for(current_user, :url => send_invite_user_path(current_user), remote: true) do |f| %>
<%= f.label :email %><br>
<%= f.text_field :email, class: 'form-control' %>
<%= f.submit "Send", class: "btn btn-primary ShareSend" %>
<% end %>
Here is the send invite controller
def send_invite
#current_page = URI(request.referer).path
#email = params[:user][:email]
InviteWorker.perform_async(current_user.id, #email)
respond_to do |format|
flash.now[:success] = "Invite sent"
format.html { redirect_to #current_page, :current_page => #current_page}
format.js { render #current_page}
end
end
It works fine when not using AJAX, but I want to try to get it to work via AJAX. The issue is that the "current_page" when I open the modal and try to send via AJAX refers to the "send_invite" action and is looking for a "send_invite" template. I want it to render WHATEVER page the user is on. To add to my difficulty I am using friendly_id.....I tried using
#page_hash = Rails.application.routes.recognize_path(URI(request.referer).path)
To try to extract the user action from the current page path, but obviously this doesn't work with friendly id.
Is there a "Rails way" of capturing the current page (ignoring the modal) and passing this to render....
I hope this is clear...
An AJAX call does not trigger a complete reload of the current page (unless explicitly told to). The request is handled in the background by javascript.
In your case you should add a view called send_invite.js.erb (i guess in your app/views/users folder - assuming that send_invite belongs to UsersController) that has some javascript that notifies the user of a successful invite and closes the modal. This view could be as simple as:
alert("Invite sent!");window.closeMyInviteModal();
This script will be executed if (and each time) the AJAX call succeed.
Clean the js responder in send_invite. This will by default render the send_invite.js view.
format.js { }
See http://guides.rubyonrails.org/working_with_javascript_in_rails.html#a-simple-example

Route Error: undefined local variable or method `events_path'

In rails 4.0.2, I am trying to implement a calendar feature along with the events.
I have referred from https://github.com/vinsol/fullcalendar-rails-engine.
But I am facing some route issue like
undefined local variable or method `events_path' for #<#<Class:0x9b8fed0>:0xb5e2e9a0>
In routes.rb file i have added,
root 'welcome#index'
mount FullcalendarEngine::Engine => "/fullcalendar_engine"
Generated routes are,
$ rake routes
Prefix Verb URI Pattern Controller#Action
root GET / welcome#index
fullcalendar_engine /fullcalendar_engine FullcalendarEngine::Engine
Routes for FullcalendarEngine::Engine:
root GET / fullcalendar_engine/events#index
get_events_events GET /events/get_events(.:format) fullcalendar_engine/events#get_events
move_event POST /events/:id/move(.:format) fullcalendar_engine/events#move
resize_event POST /events/:id/resize(.:format) fullcalendar_engine/events#resize
events GET /events(.:format) fullcalendar_engine/events#index
POST /events(.:format) fullcalendar_engine/events#create
new_event GET /events/new(.:format) fullcalendar_engine/events#new
edit_event GET /events/:id/edit(.:format) fullcalendar_engine/events#edit
event GET /events/:id(.:format) fullcalendar_engine/events#show
PATCH /events/:id(.:format) fullcalendar_engine/events#update
PUT /events/:id(.:format) fullcalendar_engine/events#update
DELETE /events/:id(.:format) fullcalendar_engine/events#destroy
In view, welcome/index.html.erb,
<%= link_to "Show Calendar", events_path %>
In fullcalendar_engine/events/index.html.erb,
<p><%= link_to 'Create Event', 'javascript:void()', id: 'new_event' %></p>
<div><div class='calendar'></div></div>
<div id="event_desc_dialog" class="dialog" style="display:none;"></div>
<div id="create_event_dialog" class="dialog" style ="display:none;">
<%= render 'form' %>
</div>
<script>
$(document).ready(function(){
$('.calendar').fullCalendar(full_calendar_options);
// page is now ready, initialize the calendar...
$('#new_event').click(function(event) {
FullcalendarEngine.Form.display()
event.preventDefault();
});
});
</script>
I guess you are using that link to show action,then it should be something like this
<%= link_to "Show Calendar", events_path(#event) %>
From the rake routes you provided
event GET /events/:id(.:format) fullcalendar_engine/events#show
the show route requires an :id,which is currently missing in your link
Update
You are calling a different controller action from the view which is not part of that controller action,so you should be giving it like this
<%= link_to "Show Calendar", :controller => 'events', :action => 'index' %>

remove image from model with rails 3 and carrierwave and jquery

I'm using Carrierwave to add and upload an image to Amazon S3. this works ok, and once the form is saved I display the image and an x box to remove it.
I would like to use ajax to handle the click event on the 'x' image' on click I would like to remove the image and clear the field on the form so that the input field is once again displayed
The image field is an attribute of the model class i am editing in the form.
Person < ActiveRecord
attr_accessible: image
the partial for this part of my form shows the image if it exists, otherwise the input file_field if it does not exists
<div class="field">
<%= image_tag #pass.background_image_url(:thumb) if #pass.background_image? %>
<%= f.file_field :background_image if #pass.background_image.to_s == '' %>
<%= content_tag :div, '', class: "delete_image_fields" if #pass.background_image? %>
</div>
I have some jquery which i can sccessful hide the image field.
jQuery ->
$('.field .delete_image_fields').click ->
$(this).parent().find('img').hide()
event.preventDefault()
The image field gets hidden no problem
What i would like to happen is
a) clear the input field from the pass object
b) submit the change (remotely)
c) delete the remote image on S3
e) re-display the file_input field for the image so it can re-selected if required
Any help or pointers would be appreciated
UPDATE
I've got this partially working to display corect fields and adjust the input link. but i'm not sure how to actually delete the file from the models attribute
I've updated the partial to the following which dispalsy either the image ro the create file button
<div class="field">
<%= f.label :background_image %><br />
<% if #pass.background_image?%>
<%= image_tag #pass.background_image_url(:thumb) %>
<%= f.file_field :background_image , style: "display:none"%>
<%= content_tag :div, '', class: "delete_image_fields" %>
<% else %>
<%= f.file_field :background_image%>
<% end %>
and updated my jquery to this
$('.field .delete_image_fields').click ->
$(this).parent().find('img').hide()
$(this).hide()
$(this).parent().find('input').val('')
$(this).parent().find('input').show()
event.preventDefault()
To delete the file, you could take advantage of the remove_mounted_field_url carrierwave creates.
From here I see two solutions, either create a new action in your controller that will only remove the file, either use the update action. I like to use as much as possible the original actions(index/new/create ...), so I will use the second solution.
You need to do an AJAX PUT request when clicking on the X box. Here what it could look like :
$('.field .delete_image_fields').click ->
$(this).parent().find('img').hide()
$(this).hide()
$(this).parent().find('input').val('')
$(this).parent().find('input').show()
event.preventDefault()
$.ajax
url: $(this).getParents('form').first().attr('action')
method: 'PUT'
data:
person:
remove_image: 1 # This will trigger the carrier wave function that remove the uploaded file
.done (data) ->
# You can do plenty if things here, for instance notify the user it's been correctly deleted
Note that this will only work on an edition form, as the url of the AJAX query which has to target the update action is taken from the form. I don't think this is a problem, as on the create form no photos is already uploaded, so there's nothing to delete.
Last thing, you could use the siblings method to find both inputs and the image

dotnetopenauth and ajax forms

I'm trying implement an openId login with Google account together with ASP.NET MVC 2 framework and DotNetOpenAuth library.
The following code is used to render login button:
<% using (Html.BeginForm("LogOnPostAssertion", "Authentication", FormMethod.Post, new { target = "_top" }))
{ %>
<%= Html.AntiForgeryToken() %>
<%= Html.Hidden("ReturnUrl", "/", new { id = "ReturnUrl" }) %>
<%= Html.Hidden("openid_openidAuthData") %>
<%= Html.OpenIdSelector(this.Page, new SelectorButton[] {
new SelectorProviderButton("https://www.google.com/accounts/o8/id", AppHelper.ImageUrl("login/google.gif")),
new SelectorOpenIdButton(Url.Content("~/Content/google.gif"))
}) %>
<% } %>
</div>
</div>
<% var options = new OpenIdSelector();
options.DownloadYahooUILibrary = false;
%>
<%= Html.OpenIdSelectorScripts(this.Page, options, null) %>
This code works fine until I want to use AJAX. I don't want to reload the whole page after user was logged in. If I change Html.BeginForm with Ajax.BeginForm the authentication stops working. "LogOnPostAssertion" action is not called.
On my site the login form is opened in popup modal dialog. I want to verify user, close the dialog and refresh user status area using javascript. As example the process should be similar to the one as at http://shopping.com
Could it be because when you switched it to AJAX that you didn't preserve the POST HTTP method?
When I tried replacing the Html.BeginForm line with this one, it worked:
<% using (Ajax.BeginForm("LogOnPostAssertion", "Auth", new AjaxOptions { HttpMethod = "POST" })) { %>
By setting a breakpoint on the LogOnPostAssertion action, I saw that it did work. But the action itself would need to be adjusted to not send redirects but rather send whatever update script is appropriate.

Resources