Execute two restful actions in one page load - ruby-on-rails

I have two models, File and Download. In the same page load, I want to read a File (serve it to the user) and create a Download.
I could either do:
GET /file/:id
PUT /file/:id/download
2 redirected to 1
Is there a correct way of handling such a situation?

I suspect what you need is just an after_filter on your file controller. Something along the lines of:
after_filter :log_download, :only => :show
protected
def log_download
# code to log a download after the show action
end
This is a lot simpler than trying to chain together request for the same effect.

Have your file download link point to a :download action, where you can log the download then render your file:
def download
DownloadLog.create(...)
render :file => ......
end

Related

Rails create file and render

In rails, is there a way (in a controller) to:
create a file
render a view or template to that file
redirect_to or render another view
I've tried all kinds of constructions, but keep getting the same error: Render and/or redirect were called multiple times in this action. Please note that you may only call render OR redirect, and at most once per action.
Otherwise; is it possible to render a template or view to a file without displaying that template/view?
thnx!
code:
def get_report
# part 1: create and render file for use with phantomjs
File.new('./vendor/assets/javascripts/graph_disk1.json','w') {|f| f.write(render "reports/disk", :layout => false)}
system `phantomjs ./vendor/assets/javascripts/highcharts-convert.js -infile ./vendor/assets/javascripts/graph_disk1.json -outfile ./app/assets/images/chart01.png -options ./vendor/assets/javascripts/resources.json`
# part 2: create odf-report and use image created bij phantomjs/highcharts-convert
report = ODFReport::Report.new("#{Rails.root}/app/report_templates/PSC2_KalScanV0.odt") do |r|
r.add_image :graphd1, "#{Rails.root}/app/assets/images/chart01.png"
send_data report.generate, type: 'application/vnd.oasis.opendocument.text',
disposition: 'attachment',
filename: 'report.odt'
end
end
the 2 parts work each, but not when called liked this (in 1 action/controller).
The solution is always easy once you've found it:
Instead of: f.write(render "reports/disk", :layout => false),
Use: f.write(render_to_string "reports/disk", :layout => false)
and voila, no more error
it seems you tried to create custom routes with render different file other than rails way, let me give you sample case, for example you have client controller but then you want to create custom method and routes other than 7 standard rails way
rails generate controller clients
inside routes.rb
resources :clients do
collection {
get :check_data # this to get data
post :import_data # this to post data
}
}
# prease remove all other routes for client controller that usually generated with get
inside app/controllers/client_controller.rb create two method for route above
def check_data
...
# the default view file is /views/clients/check_data.html.erb
# but you may also type like this below to render other file
# please note the first thing you must mention controllers name then the file name
render "clients/noname.html.erb"
end
def import_data
...
#
# here after client saved, it goes to other path instead of default
if #client.save
redirect_to courses_path
end
end

How to skip_before_filter for a redirect in a action method?

I have a controller which has several methods and one of them has a redirect at the end.
def launch
do_something
params[:hey] = "heyo"
redirect_to("/tasks")
end
All actions has a before_filter which sets some access control headers.
What i want is;
I want to have this before filter for "launch" method, but not for the redirect in it.
How can i achieve this ?
When i set this below, it removes filter for both launch method and "/tasks" redirect, but i only want to remove it for the redirect.
skip_filter :set_access_control_headers, :only => :launch
Thanks in advance!
Update:
This method lives in an engine, that's why I have different access control headers than main application. I do not want to mess with main applications code since i create specific engine and routes for each customer.
And the redirect in the end goes to main application.
You can set param in your redirect and in filter check if param is not exist than skip
Example: redirect_to edit_multiple_items_path, :notice => 'items updated', {:page => ##, :method => 'GET'}
It might be because I focused too much on doing it the "Rails" way.
I fixed the issue by simply removing the headers manually just before the redirect and it all worked fine now.
headers.delete('Access-Control-Allow-Origin')
headers.delete('Access-Control-Request-Method')
headers.delete('Access-Control-Allow-Methods')
redirect(/tasks?#{options.to_query})
Thanks for the answers though!

Rendering on specific pages through application.html.erb file?

I have a search box that I only want to render on particular pages through the navigation section in my application.html.erb file.
How do I set exceptions? Is this done through the main application controller?
There are several ways to do this.
Most obvious way is to use an instance variable for flagging.
In your application.html.erb
<%= render 'search' if #search_box %>
And wherever you want to show the search, set the flag instance variable to true.
def show
#search_box = true
...
end
Edit
You might also want to utilize Rails' filters in your controllers if you want multiple actions to show search.
before_action :flag_search_box, :only => [:show, :new, :all_kinds_of_controller_actions_where_i_wanna_show_search]
...
private
def flag_search_box
#search_box = true
end
I might suggest to put the search box not in the application.html page but maybe in the separate html pages that you want it to render on. You could make the search a partial so that you could access it from the other pages with just one line of code.

Add RESTful Action

The source of my information is section 2.9 here:
[http://guides.rubyonrails.org/routing.html#connecting-urls-to-code][1]
What I'm trying to do is add a custom action "search" and corresponding view.
So, as it says to do in the documentation, I've added this code in my config/routes.rb file:
resources :dimensions do
collection do
get "search"
end
end
I've also defined in the dimensions_controller file:
def search
#dimensions = Dimension.all
respond_to do |format|
format.html # search.html.erb
format.json { render json: #dimensions }
end
end
I then stopped and restarted the rails server, but when I navigate to /dimensions/home, I'm still getting this error message:
Couldn't find Dimension with id=search
Also showing that my parameter is:
{"id"=>"search"}
So am I just missing another bit of code that gives the instruction to interpret /dimension/search as a collection action as opposed to the show action?
I've already confirmed that search_dimensions_path exists, so I know that the resource block in the routes.rb file is actually adding paths. It's just interpreting them as a separate search action that's giving me trouble.
Thanks for your time.
This code should work fine. Can you show us your routes.rb file?
On a side note, you probably don't want to have a separate action for searching, using the index action is the preferred way.
Found the issue:
I had to make the resource declaration in my config/routes.db file for dimensions after creating the collection action, like so:
resources :dimensions do
collection do
get "search"
end
end
resources :dimensions
Then everything worked as expected.

Rails: Easiest way to provide file downloads?

G'day guys, currently have almost finished writing a rails application that allows a CSV download of the database. This is generated when the index is first viewed.
Is there an easy way to insert a link to a helper that returns a CSV document? That is to say is it easy to insert links to helpers? This would make a lot of problems I've been having much easier
If you sticked to the general conventions, then you registered a mime-type for csv and return the csv file content via your #index action. So your link helper would be like this:
link_to 'export as csv', posts_path(:format => :csv)
If, in exchange, your file is generated WHEN index is first view but NOT BY Rails, you may want to avoid standart render and call send_data or send_file instead (check the api for them).
# in your controller:
def index
# your suff here
#csv_path = find_or_generate_csv_file
send_data #csv_path, :type=>"text/csv", :disposition=>'attachment'
end
protected
def find_or_generate_csv_file
#your file generation logic
end

Resources