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".
Related
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?
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
In an ERB Rails view
<%= link_to("Destroy", foos_path(1), :method => :delete, :confirm => "Are you sure?") %>
With a link_to like the above you can process the delete for a foo with an ID of 1.
How do make it remote and (a) still control being redirected to a page of my control or (b) call custom JavaScript (the goal of which would be jQuery to refresh a list)
Add :remote => true to the link_to will create a remote link.
In your controller method at the end put
respond_to do |format|
format.js { render "my_method"}
end
You can omit the name of the ajax file if it's the same name as the method.
In my_method.js.erb simply call javascript functions, and you can embed erb ie:
$("#someDiv").load(<%= #some_value $>);
You can redirect to another page using standard javascript/jquery if you choose.
I'm trying to generate a PDF file using AJAX call in Rails3. The following code generates a PDF file which I have created using PRAWN gem.
<%= link_to "Generate pdf", books_path(#book, :format => 'pdf') %>
I do not want user to view the PDF until they order it. So, the goal is to create a PDF file in the server.
Any ideas or thoughts much appreciated.
Use this, make sure your remote action does not return the PDF, but simple generates and stores it on the server.
link_to "Generate PDF", prepare_books_path(#book), :remote => true, :method => :put
This will work in Rails 3. If you're using jQuery, make sure to read this article on how to set things up correctly.
Your controller action may look like this:
def prepare
# Do your thing to generate the PDF
render :text => "PDF Generated", :status => 200
end
I used the PUT-method because you are altering the state of your data (e.g. you are generating something new, you don't want a bot or crawler to automatically call that).
Firstly, it beats me why you would do something on a request like generating a PDF, when the user is not expecting that action. Isn't better to only generate the pdf when the user requests for it?
Thanks Ariejan.
I modified your code as following and it did just what I wanted.
<%= link_to "Generate Story Book", pdfbook_stories_path(:format => 'pdf'), :remote => true %>
And for the controller,
def pdfbook
#stories = current_account.stories
respond_to do |format|
format.pdf {}
end
end
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