I want to create a custom action in Rails which will update views and print some info on div.
I use that gem for file upload:
https://github.com/valums/file-uploader/blob/master/client/fileuploader.js
After successful upload I want to update with ajax page how many miliseconds it takes.
In old Rails I would write that with:
def set_tab
#diff = count_miliseconds_method
render :update do |page|
page.replace_html "place_menu", render( :partial => 'place_menu')
end
end
But I cant figure out how to do that in Rails 3.1.
My custom action controller code:
def custom
[...] # Here everything works OK
start_time = Time.now
Some_method
end_time = Time.now
#diff = ((end_time - start_time)*100).to_i # counted miliseconds
respond_to do |format|
format.json {render :json => {:success => true, :time => #diff}, :status => :created, :location => custom_words_path}
end
end
My custom.js.erb code
var el = $('#upload-log');
el.append("#{#diff} ms");
Unfortunately this doesnt work. I get response e.g.
{"success":true, "time":324}
but js.erb file doesnt get executed and page doesnt containt information about miliseconds.
Any idea how to fix that?
Update
Github repo:
https://github.com/there-is-no-spoon/Anagram
To execute js.erb file you have to pass
:format => :js
to your path generating method - for example:
link_to "My custom action", my_action_path(:format => :js)
You're returning JSON now (in Rails 3.1) not a chunk of string containing Javascript (as was the case before).
You need to write your code which handles your result where you make the Ajax Call. I assume you're using jQuery. So where you make the Ajax call, implement the success handler and do the
var el = $("#upload-log");
...
stuff there.
Basically server does not return Javascript anymore, it is completely on the client side only.
You need to implement the onComplete method of your file upload plugin. Read the manual of your js plugin, its mentioned clearly.
Related
In my Rails 6 app I have a very simple controller that displays download links to a user's Stripe invoice PDFs:
class ReceiptsController < ApplicationController
before_action :signed_in_user
def index
receipts = current_account.receipts
end
def show
receipt = current_account.receipts.find(params[:id])
stripe_invoice = Stripe::Invoice.retrieve(receipt.stripe_invoice_id)
redirect_to stripe_invoice.invoice_pdf
end
end
Since Stripe doesn't provide permanent invoice URLs (please correct me if I am wrong), I am storing each invoice's Stripe ID in the database and then use that ID to lookup the current URL to the invoice PDF from the Stripe API.
The problem is that this works most of the time but not all the time. The spec that I created for the controller show action fails in about 20 % of cases because the two URLs do not match:
describe ReceiptsController, :type => :controller do
before :each do
#account = FactoryBot.create(:activated_account)
#user = #account.users.create(FactoryBot.attributes_for(:user))
sign_in(#user)
end
describe 'GET #show' do
# The implementation details of this block don't really matter
before :each do
Customers::FindOrCreate.call(#account)
stripe_subscription = Subscriptions::CreateRemote.call(#account,:payment_behavior => "default_incomplete")
#stripe_invoice = stripe_subscription.latest_invoice
#receipt = Receipts::Create.call(#stripe_invoice)
end
# This test fails in about 20 % of cases because the redirect does not go to #stripe_invoice.invoice_pdf but a slightly different URL
it "redirects to Stripe invoice PDF" do
get :show, :params => {:id => #receipt}
expect(response).to redirect_to #stripe_invoice.invoice_pdf
end
end
end
How can this be? Does the invoice_pdf property of a Stripe invoice change every few seconds? I've been trying to work this out for days now but can't get my head around it.
Addition:
This is a typical test failure that I get quite often:
Expected response to be a redirect to <https://pay.stripe.com/invoice/acct_105jfm2HzYSlmhv7/test_YWNjdF8xMDJqc20yS3pZUmxzaHc0LF9NMGZONnFzNUpPTjlObVprd0hvdGpIdWFUamJHTTVxLDQ3Njc3MDY30200oOxX3A1/pdf?s=ap> but was a redirect to <https://pay.stripe.com/invoice/acct_105jfm2HzYSlmhv7/test_YWNjdF8xMDJqc20yS3pZUmxzaHc0LF9NMGZONnFzNUpPTjlObVprd0hvdGpIdWFUamJHTTVxLDQ3Njc3MDY402001iYCSUbn/pdf?s=ap>.
Expected "https://pay.stripe.com/invoice/acct_105jfm2HzYSlmhv7/test_YWNjdF8xMDJqc20yS3pZUmxzaHc0LF9NMGZONnFzNUpPTjlObVprd0hvdGpIdWFUamJHTTVxLDQ3Njc3MDY30200oOxX3A1F/pdf?s=ap" to be === "https://pay.stripe.com/invoice/acct_105jfm2HzYSlmhv7/test_YWNjdF8xMDJqc20yS3pZUmxzaHc0LF9NMGZONnFzNUpPTjlObVprd0hvdGpIdWFUamJHTTVxLDQ3Njc3MDY402001iYCSUbn/pdf?s=ap".
In ActiveAdmin I'm trying to get a value from a form when I press an action_item on the dashboard, but I'm not sure exactly how to do that this is what I have so far, and it runs, but I would like to be able to pass a parameter for different method calls.
ActiveAdmin.register_page "Dashboard" do
menu :priority => 1, :label => proc{ I18n.t("active_admin.dashboard") }
page_action :scrape, :method => :post do
#The scraper works, but I don't know how to pass the info
#from the form from below into this method
# scrape = Scraper.new
# scrape.scrape
redirect_to admin_dashboard_path, :notice => "Ran the scraper!"
end
action_item do
link_to "Run Scraper", admin_dashboard_scrape_path, :method => :post
end
content :title => proc{ I18n.t("active_admin.dashboard") } do
panel "Run Course Scraper" do
para "Run the course webscraper to pull current class list and insert into the Course table in the database"
form do |f|
f.input "Session"
end
end
end
end
I want to get the input form the form where it says session to pass to the page_action :scrape somehow, any ideas?
You could to try to add controller actions to the dashboard page and add f.buttons to the form etc.
Using javascript should also work I guess.
I am creating a pdf file in the latest version of the Prawn library (v1.0.1rc) in Rails (3.1.1) and when I run my code it generates the PDF into the root of the application.
I don't want this. I want it to render the output into user's browser window, without saving it locally to the server.
Please tell me how I can achieve this. Here are my files:
views/foo/show.pdf.erb:
<%=
require 'prawn'
pdf = Prawn::Document.new(:page_size => 'LETTER', :page_layout => :landscape, :margin => 50, :top_margin => 20, :bottom_margin => 50)
.....
render_file("foo.pdf")
%>
controllers/foo_controller:
class AuditsController < ApplicationController
before_filter :authenticate_user!
layout 'application'
can_edit_on_the_spot
respond_to :html, :xml, :js, :pdf
def index
#audits = Audit.all
respond_with #audits
end
def show
#audit = Audit.find(params[:id])
respond_with #audit do |format|
format.pdf { render :layour => false }
end
end
Gemfile
gem 'prawn'
/config/initializers/mime_types.rb
Mime::Type.register "application/pdf", :pdf
AuditsController
def show
#audit = Audit.find(params[:id])
respond_to do |format|
format.html
format.pdf do
pdf = Prawn::Document.new
pdf.text "This is an audit."
# Use whatever prawn methods you need on the pdf object to generate the PDF file right here.
send_data pdf.render, type: "application/pdf", disposition: "inline"
# send_data renders the pdf on the client side rather than saving it on the server filesystem.
# Inline disposition renders it in the browser rather than making it a file download.
end
end
end
I used to use the prawnto gem before Rails 3.1, but it doesn't work without a bit of hacking anymore. This is a much cleaner way to instantiate and display the PDF object in 3.1 by accessing Prawn directly.
I got this technique straight from one of Ryan Bates' Railscasts. Been using it ever since. You can view that specific episode here. He goes into much more detail about subclassing Prawn and moving the PDF generating code out of the controller. Also shows a lot of useful Prawn methods to get you started. Highly recommended.
A lot of the episodes are free, but that revised Prawn episode is one of those that are only available with a paid subscription. At $9/month though, a subscription quickly pays for itself.
I find the best way to send a pdf to the client's browser is to put the download into a link. Often you need to generate a pdf after form submission, but also need to redirect to another page.
You can't redirect and send the pdf simultaneously, but you can redirect and then provide a download link, like so:
First add gem 'prawn' to your gemfile. Bundle. Then do the following:
Link to your special printing action in your view
<%= link_to 'print ticket', print_ticket_path %>
route to special printing action in routes.rb
match 'print_ticket', to: 'tickets#print_ticket'
action that sends the outputted file (change per your needs):
def print_ticket
if session[:token]
#pdf = generate_pdf(session[:token])
send_data(#pdf, :filename => "output.pdf", :type => "application/pdf")
end
end
private
def generate_pdf(token)
Prawn::Document.new do
formatted_text [ { :text=>"xxx.org", :styles => [:bold], :size => 30 } ]
move_down 20
text "Please proceed to the following web address:"
move_down 20
text "http://xxx.org/finder"
move_down 20
text "and enter this code:"
move_down 20
formatted_text [ { :text=>token, :styles => [:bold], :size => 20 } ]
end.render
end
I am trying to do Ajax login with Devise, as explained here: http://jessehowarth.com/2011/04/27/ajax-login-with-devise#comment-5 (see comment from jBeasley).
My controller is attempting to return
class Users::SessionsController < Devise::SessionsController
def failure
render :json => {:success => false, :errors => ["Login failed."]}
end
end
which results in this error:
NameError (wrong constant name ["{\"success\":false,\"errors\":[\"Login failed.\"]}"]Controller):
and Firebug showing [500 Internal Server Error].
How can I fix this? I am running Rails 3.1 and devise 1.4.5.
Thanks!!
Did you do the step recommended by Jeff Poulton in comment #4? The :recall option in 1.4.5 looks to be completely incompatible to older versions. It now requires you send the controller, whereas in the tutorial you're following he just sends the action (the old way).
In your case, :recall => :failure must be changed to :recall => "users/sessions#failure" in Devise 1.4.5.
This is because of the way the controller for the failure action is determined. In older versions, it was simply pulled from the params.
def recall_controller
"#{params[:controller]}.camelize}Controller".constantize
end
# called via recall_controller.action(warden_options[:recall]).call(env)
In 1.4.5, it expects a string specifying the controller and action, in the style of routes:
def recall_app(app)
controller, action = app.split('#')
controller_name = ActiveSupport::Inflector.camelize(controller)
controlller_klass = ActiveSupport::Inflector.constantize("#{controller_name}Controller")
controller_klass.action(action)
end
# called via recall_app(warden_options[:recall]).call(env)
It would seem as though your app is actually passing the JSONified hash of options to recall_app, which, lacking a '#', isn't being split, and the entire string is concatenated to "Controller" to attempt to ascertain the failure controller's class.
You are missing the return in
def failure
return render:json => {:success => false, :errors => ["Login failed."]}
end
Does that make a difference?
I have the following which renders information from my groups in through xml, this code works well.
respond_to do |format|
format.html # index.html.erb
format.xml {
groups_xml = #groups.to_xml(:include => [:enrolled_users, :tracks, :events])
render :xml => courses_xml
}
end
end
In a second part I want add url picture to this xml.
Currently I use the following code to get the picture url, and know I need to add it to the xml render but I don't know how
picture = Groups.find(params[:id]).groups.logo.public_filename(:avatar)
I'm looking for an answer for 1 month and now I don't know where I can find out.
Assuming that each group has a logo that you're trying to include in the xml, you could add a method to the group model like:
class Group
def avatar_filename
logo.public_filename :avatar
end
end
and then add :avatar_filename to the :include option you are already passing to to_xml, like this:
#groups.to_xml(:include => [:enrolled_users, :tracks, :events, :avatar_filename])
Is this what you're looking for?