Popup/New Window + Redirect_to + Rails - ruby-on-rails

It is possible to redirect_to some url from the controller and open the url in the new window at the same time ?

Not really from the controller action.
A redirect is an HTTP response with a 301/302 status code and an empty body in Rails. As the body is empty, you don't have any way to include extra processing for the browser (such as javascript etc to open a new window).
Assuming you have the the controller action triggered via a hyperlink on another page, your best bet would be to have that open in a new window. Then the redirect target would be displayed.
Either that, or render the same page again as a regular response (no redirect), and insert some javascript when the page loads to open a new window

#madlep "your best bet would be to have that open in a new window"
Thanks for that one. Works perfectly!
view:
<%= link_to "Buy this product", buy_path, target: "_blank" %>
controller:
def buy
...
redirect_to link
end

Searched a little and found a solution... it's not on the controller (as I originally wanted too but it's quite easy...) in your view:
<%= link_to '', {:controller => 'assignments', :action => 'overall_report_gen', :evaluator_relations => #evaluator_relations}, :target => '_blank', :id => 'reporte' %>
<script language="JavaScript">
document.getElementById('reporte').click();
</SCRIPT>
so, with '' as the display string in the link_to, you get an invisible link,
with the :target => '_blank' the link, when clicked will open in a new window
and the :id => 'reporte' is needed in order to click the link with javascript.
so just place the same id in the link_to and in the string in the javascript, and that's it
remember to place the javascript snippet AFTER the link_to so as to wait the element is loaded

Related

Rails - Change boolean value on link click

In my app I have user notifications where the user gets notified for certain actions. These notifications are being shown in a dropdown from the navbar (like Facebook or S.O.). All of the notifications have a boolean attribute called :read and are default set to false. I'm using bootstrap with the dropdowns (in case that helps).
I want to create a method where when the user clicks to open the dropdown, all of their unread notifications become read.
Here is what I have so far for the method.
def read_notifications
PublicActivity::Activity.where(recipient_id: current_user).where(read: false).update_all(:read => true)
end
This updates all of the current user's notifications to :read => true when the method is called. In the view here is what I had so far for the dropdown link.
<%= link_to read_notifications_path, :class => "dropdown-toggle notifications_icon", :'data-toggle' => "dropdown", :controller => "application", :action => "read_notifications", :method => :post do %><% end %>
and the routes.rb I had this.
match "/read" => "application#read_notifications", :as => "read_notifications", via: 'post'
Now I know what I have is wrong, but even so when I click the link it does switch all of the user's notifications to read, it just acts also as a link (duh) and goes to a different page.
As you know, the link on a bootstrap dropdown is "#".
Does anyone know how I can set this up properly where when the user clicks the notification link in the navbar, ALL it does is open the dropdown and change the boolean value to true for all notifications.
I know this is possible, I just haven't been able to figure it out yet.
Thanks for taking a look at it.
EDIT
JS file
$(".notifications_icon").on("click", function(){
$.post("/read", function(data){
$('.notification_badge').text("");
});
});
View
<%= link_to "#", :class => "dropdown-toggle notifications_icon", :'data-toggle' => "dropdown" do %>
<span class="notification_badge"><%= find_unread_notifications_count(current_user) %></span>
<% end %>
This is Posting to the /read to read all of the notifications but it's not updating the count
You want a dash of unobtrusive JS. For example, SO has a class js-inbox-button that, when clicked, triggers updates on unread counts (both client and server). I won't dig into their JS source, but it's fairly simple to build.
You seem to already have a relevant class (notifications_icon), though you might want to use something else. When the link is clicked, use jquery $.post.
$(".notifications_icon").on("click", function(){
$.post("/read", function(data){
// remove unread count
$('.notification_badge').text('');
});
});
Now this is a very basic implementation. Couple of suggestions:
Only make requests when necessary (check for unread count on page first)
Use a data attribute on the link to pass /read path. That way you can still use your path helpers instead of hardcoding a path.
Store the above JS in a separate file (unobtrusive)
AJAX.
By adding remote: true you're starting with AJAX. Now the call goes to your path, and nothing happens! yay!
You want something to happen, though. So in your controller (I wouldn't do it in the application_controller, if I were you... activities_controller.rb maybe?):
controllers/activities_controller.rb
def read_notifications
PublicActivity::Activity.where(recipient_id: current_user).where(read: false).update_all(:read => true)
respond_to do |format|
format.js
end
end
You're on your way to Asynchronous loading! Now you need a js file to match it. So, since you've already moved this action to the activites, in your view, you'll have a new js.erb file to create (notice that it's in the same folder in the views as the controller name, and the file is named after the action):
views/activities/read_notifications.js.erb
$('#your_menu_div').html("<%= j render partial: 'activities/notifications' %>");
Now you create a partial (views/activities/_notifications.html.erb) that gets rendered into your pulldown menu.
Clear as mud?

UJS - where do I put the js.erb?

My articles can appear on several sites, so as well as an article model with title, body etc and a site model with site_id, site_name etc, I have I have an article_site_permission model, with article_id, site_id and visible which can be either true or false.
On my article edit page, I've done a button_to:
<%= button_to 'Hide', article_site_permission_path(:id => #article_site_permission_id, :article_site_permission => {:visible => "false"}), :method => :put %>
This works - it changes the permission to false. And I can show the Show button which does the reverse.
Now I want to refresh the div that has the button in it by adding :remote => true to the button link. But where do I put my javascript?
Is it in the article_site_permission view - even though I'm looking at a view of the article itself?
Is it called update.js.erb?
Thanks for your help.
Update for clarity.
My button is on the articles/edit page. The button updates article_site_permissions. I want to go back to articles/edit and refresh the div that has the button in it.
I must edit the update controller for article_site_permissions, but where do I put the js to refresh the div?
In your controller, redirect to the action you want (index, show, etc.). Do a
respond_to do |format|
format.js
end
under that action in your controller. Then, in the corresponding view, have a file named
index.js.erb
Or replace index with whatever action, just be sure to give it the same name as the action that's calling it.
EDIT
I should also mention you are correct in adding the remote true to your button. It's hard to tell from your question what action you're trying to reach in which controller. If you're trying to access the show action of the ArticleSitePermission controller, you're doing well. However, it seems like you're not trying to route to show. Check out this link for more info on routing to different actions.
EDIT 2
This should do it.
<%= link_to 'Click me', {:controller => "article", :action => "update", :id => #article_site_permission_id },
:remote => true %>
Also, if all you want to do is redirect to the article, you don't need to do js. Just redirect to articles#show

Can not send a ajax request from a form_tag

I am trying to send a ajax request from a form tag, but no XHR request is sent. If I do the same from a link everything works perfectly.
Here's the view from which I can send the request either from a link or a form:
<div id="request_test">
<%= link_to "test", explorer_test_path(:format => :js), :remote => true %>
<%= form_tag explorer_test_path(:format => :js), :id => "testform", :remote => true, :method => :get do %>
<%= submit_tag "Send test request"%>
<% end %>
</div>
<div id="response_test"></div>
In my controller I then check if it is a XHR request or not and then render the javascript responding to the ajax request:
def test
if request.xhr?
logger.debug "xhr"
else
logger.debug "not xhr"
end
respond_to do |format|
format.js
end
end
My test.js.erb is very simple:
$("#response_test").html("<b>hi</b>");
The result is that if I click the link I get the behavior I am looking for, ie that the response_test div reads "hi". If I submit the form I simply get the javascript in test.js.erb written out as a string and the server log telling me that the form didn't submit a XHR request. If i debug the whole thing in firebug I get the same result, the link sends an ajax request, the submitted form does not. In both cases my console tells me that the server is processing the request as JS, so it shouldn't be any data-type problem.
Running Rails 3.0.4 with jquery UJS.
Thankful for any hints to what the problem might be, I have tried to figure this out for quite some time now but since I am relatively new to Rails I suspect that I am missing something basic.
UPDATE: Adding the following javascript from (http://www.alfajango.com/blog/rails-jquery-ujs-now-interactive/) fixes the problem, which suggests that the :remote => true on my form tag isn't found or interpreted correctly by the jquery ujs. I see this as a workaround more than a permanent fix so if anybody have any idea of what is wrong in my original code I would be very grateful.
$('#testform').live('submit', function(e) {
$.rails.handleRemote( $(this) );
e.preventDefault();
});

Rails: send_file not causing download, links to 'show' controller method instead

First time using rails, I'm trying to create a download link to get something off the file system.
In my view, I've got
<%= link_to 'Show', upload, :method => :download %>
and my 'download' method in my controller looks like:
def download
#upload = Upload.find(params[:id])
send_file '/data_store/50692.pdf'
This is needed because I have restrictions on who can view this pdf, but on this page, I get linked to
http://localhost:3000/uploads/10
(10 is the id of this 'upload')
and on that page, I get the error
Unknown action
No action responded to 10. Actions: clearance, create, destroy, download, edit, index, is_admin, new, show, su_required, and update
I want it instead to stay on the same page, and offer the user a download prompt, but I'm not sure what I'm doing wrong.
Ideally you should be looking into a Ajax call if you'd want to stay on the same page and offer the user a download prompt, but the code given below would also work. Upon clicking the "download" link it'll open a new tab/window,offer the user a download prompt and close the tab/window.
Also the :method parameter to link_to tells it which HTTP method (POST,GET,DELETE,PUT) to use. To reference the "download" method in your controller use the :action parameter.
view
----
<%= link_to 'Show', upload, :action => :download, {:target => "_blank"} %>
controller
----------
return send_file '/data_store/50692.pdf', :type => "application/pdf", :filename => "50692.pdf"
I think it is a problem in the calling download method.
Try this one
<%= link_to "Show",:controller=>'controllername',:action=>'download',:id=>upload.id %>
You must pass your controller name in the place "controllername".

Rails controller not rendering correct view when form is force-submitted by Javascript

I'm using Rails with jQuery, and I'm working on a page for a simple site that prints each record to a table. The only editable field for each record is a checkbox. My goal is that every time a checkbox is changed, an ajax request updates that boolean attribute for the record (i.e., no submit button).
My view code:
<td>
<% form_remote_tag :url => admin_update_path, :html => { :id => "form#{lead.id}" } do %>
<%= hidden_field :lead, :id, :value => lead.id %>
<%= check_box :lead, :contacted, :id => "checkbox"+lead.id.to_s, :checked => lead.contacted, :onchange => "$('#form#{lead.id}').submit();" %>
<% end %>
</td>
In my routes.rb, admin_update_path is defined by
map.admin_update 'update', :controller => "admin", :action => "update", :method => :post
I also have an RJS template to render back an update. The contents of this file is currently just for testing (I just wanted to see if it worked, this will not be the ultimate functionality on a successful save)...
page << "$('#checkbox#{#lead.id}').hide();"
When clicked, the ajax request is successfully sent, with the correct params, and the action on the controller can retrieve the record and update it just fine. The problem is that it doesn't send back the JS; it changes the page in the browser and renders the generated Javascript as plain text rather than executing it in-place.
Rails does some behind-the-scenes stuff to figure out if the incoming request is an ajax call, and I can't figure out why it's interpreting the incoming request as a regular web request as opposed to an ajax request.
I may be missing something extremely simple here, but I've kind-of burned myself out looking so I thought I'd ask for another pair of eyes. Thanks in advance for any info!
In your controller you need to specify the proper response. Since you didn't post the controller I'll just try to fill in the blanks.
def update
# Update something
respond_to do |format|
format.js # this renders your rjs file
end
end
Specifying the format tells the rails app to interpret the javascript instead of just sending it back as text.
The other option instead of using rjs is to do an inline rjs block like this:
render :update do |page|
page.replace_html 'user_list', :partial => 'user', :collection => #users
page.visual_effect :highlight, 'user_list'
end
Only use the inline rjs if you will be doing minimal changes to the interface that can be put into one or two lines. Anything more should be in it's own rjs file.
This question is related to this one, but the answer varies slightly. I had to create a new way to submit the form, since the default jQuery submit() method does not submit as a 'script' and certainly does not fire the code that Rails generates in the onsubmit="..." handler via the form_remote_tag helper.
The solution was to create a new function as the linked answer suggests, but the contents are slightly different:
jQuery.fn.submitWithAjax = function() {
jQuery.ajax({data:jQuery.param(jQuery(this).serializeArray()) + '&authenticity_token=' + encodeURIComponent('<%= form_authenticity_token %>'), dataType:'script', type:'post', url:'/update'});
return false;
};
This is brittle right now-- notice that I insert rails' form_authenticity_token into the Javascript, but really the method (post) and the url (/update) should also be generated rather than hardcoded.
Things are working A-OK now.

Resources