Save xlsx file to disk in Sidekiq as background - ruby-on-rails

I am trying to generate excel file in background by using axlsx and save it (Rails4.2). In GitHub page of axlsx, it says As of Rails 4.1 you must use render_to_string to render a mail attachment. However, it throws me a error NoMethodError: undefined method 'render_to_string' for #<CreateExcelSheetWorker:0x007fbccf51db30>
My worker class:
class CreateExcelSheetWorker
include Sidekiq::Worker
include Sidetiq::Schedulable
recurrence { daily }
def perform()
model = SomeModel.where(wanted: true).order(started_at: :desc)
xlsx = render_to_string handlers: [:axlsx], formats: [:xlsx], template: "template/file", locals: {model: model}
path = "/tmp/a.xlsx"
File.open(path, "w+") do |f|
f.write(xlsx)
end
end
end
I cannot figure out how to fix this, any help appreciated.

That render_to_string comment is for usage of the gem in actionmailers. Outside of any kind of view context, you'll have to use xlsx builder api directly. Something like this:
package = Axlsx::Package.new do |p|
p.workbook.add_worksheet(name: "Summary") do |sheet|
sheet.add_row ["foo", 1]
end
end
File.write(filename, package.to_stream.read)

Sergio's answer is fine. But, if you are wanting to use the axlsx_rails template, you can use this example, which builds a fake view context to render the template:
require 'abstract_controller'
require 'action_controller'
require 'action_view'
require 'active_record'
# require any helpers
require './app/helpers/application_helper'
# active record only if data is here
require './app/models/widget'
ActiveRecord::Base.establish_connection(
adapter: 'sqlite3',
database: 'db/development.sqlite3'
)
ActionController::Base.prepend_view_path "./app/views/"
# place data in view_assigns
view_assigns = {widgets: Widget.all}
av = ActionView::Base.new(ActionController::Base.view_paths, view_assigns)
av.class_eval do
# include any needed helpers (for the view)
include ApplicationHelper
end
# normal render statement
content = av.render template: 'widgets/index.xlsx.axlsx'
# do something with content, such as:
File.open("/tmp/with_runner.xlsx","w+b") {|f| f.puts content }
https://gist.github.com/straydogstudio/dceb775ead81470cea70

Related

Wicked pdf, failed to load PDF document

I am trying to implement the gem wicked_pdf . After initial difficulties (fatal error (exception reentered)), I managed to start the server. I set up a pdf with the content "Hello world" for the test, but every time I want to open it, I get a "failed to load PDF document" notification
Controller
def index
respond_to do |format|
format.html
format.pdf do
render pdf: "index.pdf.haml",
layout: 'pdf.html.haml',
page_size: 'A4',
disposition: 'inline'
end
end
end
index.pdf.haml
Hello world
config/initializers/wicked_pdf.rb
# WickedPDF Global Configuration
#
# Use this to set up shared configuration options for your entire application.
# Any of the configuration options shown here can also be applied to single
# models by passing arguments to the `render :pdf` call.
#
# To learn more, check out the README:
#
# https://github.com/mileszs/wicked_pdf/blob/master/README.md
class WickedPdf
module PdfHelper
remove_method(:render)
end
end
WickedPdf.config = {
# Path to the wkhtmltopdf executable: This usually isn't needed if using
# one of the wkhtmltopdf-binary family of gems.
# exe_path: '/usr/local/bin/wkhtmltopdf',
# or
# exe_path: Gem.bin_path('wkhtmltopdf-binary', 'wkhtmltopdf')
# Layout file to be used for all PDFs
# (but can be overridden in `render :pdf` calls)
# layout: 'pdf.haml',
# Using wkhtmltopdf without an X server can be achieved by enabling the
# 'use_xvfb' flag. This will wrap all wkhtmltopdf commands around the
# 'xvfb-run' #command, in order to simulate an X server.
# use_xvfb: true,
}
config/initializers/mime_types.rb
# frozen_string_literal: true
# Be sure to restart your server when you modify this file.
# Add new mime types for use in respond_to blocks:
# Mime::Type.register "text/richtext", :rtf
Mime::Type.register "application/pdf", :pdf
Link to Screenshot: https://drive.google.com/file/d/1ujt8ANq16SrmSHJk45APMXXxm1l5q5ic/view?usp=sharing
Ok, so I downgraded wicked_pdf to version 1.4.0 and I removed:
class WickedPdf
module PdfHelper
remove_method(:render)
end
end
From config/initializers/wicked_pdf.rb, and now it works.

NameError: uninitialized constant AppName::Loader::ModelImport::MyModel

I have a namespace issue. MyModel is just a normal Rails Model. However, my code seems to be namespacing it under the namespace I created, I need a way to reference it directly without the AppName::Loader::ModelImport namespace.
Error:
NameError: uninitialized constant AppName::Loader::ModelImport::MyModel
Rake task:
require 'csv'
require_relative '../appname/loader/model_import'
namespace :app_name do
namespace :loader do
desc "Loads data into Database"
task model_import: :environment do
include AppName::Loader::ModelImport
end
end
end
Service Object
./appname/loader/model_import.rb
module AppName
module Loader
module ModelImport
record_set = []
file_name = File.join(Rails.root, 'lib','appname','loader','data' ,'data.txt')
CSV.open(file_name, "r", { :col_sep => "\t", quote_char: nil, row_sep: "\r\r\n" }).each do |row|
record_set << MyModel.new(
company_name: row[1],
address1: row[2],
address2: row[3],
city: row[4],
state_code: row[5],
zip_code: row[6]
)
end
MyModel.import record_set
end
end
end
I tried:
::MyModel.new()
and also got the >>NameError: uninitialized constant MyModel, so I wonder if rails is not loading properly. However, I thought task model_import: :environment do loads Rails.
My application.rb file has..
config.eager_load_paths << Rails.root.join("lib")
If I use Pry, I can see the 'Rails' constant is loaded. However, I can not access any of my models. For example, User does not load, nor any other.
Solution per comments by Tom Lord:
require needed to be evaluated after the environment has been loaded.
If you write a module the code inside it may automagically get executed just because you required the module. For example:
module AppName
module Loader
module ModelImport
puts 'wtf' # this may get run but you won't see it
end
end
end
However if you have at least method defined it can be called
module AppName
module Loader
module ModelImport
def self.wtf
puts 'wtf'
end
end
end
end
Now if this file is saved in lib/app_name/loder/model_import.rb you can run it like this:
require_or_load 'lib/app_name/loader/model_import'
# and now you can do
AppName::Loader::ModelImport.wtf
=>wtf
So you need to first define a usable module, then you can require it, then you can call methods on it.

Can we apply dashing for rails application

Now I am dealing with dashing from here http://shopify.github.io/dashing/ I created an dashing app using Sinatra and I added some more 3rd party API's everything is working well. Now I want to run the app with rails I tried every thing is working fine but "event" method can't be called by server.Actually it is in dashing.rb file in my lib directory it is like this.
require 'sinatra'
``require 'sprockets'
require 'sinatra/content_for'
require 'rufus/scheduler'
require 'coffee-script'
require 'sass'
require 'json'
require 'pry'
module Dashing
SCHEDULER = Rufus::Scheduler.start_new
class App < Sinatra::Base
if Rails && Rails.root
set :root, Rails.root
set :root_path, '/dashing/'
Rails.application.config.assets.precompile += %w( dashing/application.js dashing/application.css )
set :views, Rails.root.join('app', 'dashing', 'dashboards')
set :widget_path, "#{settings.root}/app/dashing/widgets/"
set :lock, true
set :threaded, true
else
set :root, Dir.pwd
set :root_path, '/'
set :sprockets, Sprockets::Environment.new(settings.root)
set :assets_prefix, '/assets'
set :digest_assets, false
['assets/javascripts', 'assets/stylesheets', 'assets/fonts', 'assets/images', 'widgets', File.expand_path('../../javascripts', __FILE__)]. each do |path|
settings.sprockets.append_path path
end
set server: 'thin'
set :public_folder, File.join(settings.root, 'public')
set :views, File.join(settings.root, 'dashboards')
set :widget_path, File.join(settings.root, 'widgets')
end
set connections: [], history: {}
set :default_dashboard, nil
set :auth_token, nil
helpers Sinatra::ContentFor
helpers do
def protected!
# override with auth logic
end
end
get '/events', provides: 'text/event-stream' do
protected!
stream :keep_open do |out|
settings.connections << out
out << self.latest_events
out.callback { settings.connections.delete(out) }
end
end
get '/' do
begin
redirect settings.root_path + (settings.default_dashboard || self.first_dashboard).to_s
rescue NoMethodError => e
raise Exception.new("There are no dashboards in your dashboard directory.")
end
end
get '/:dashboard' do
protected!
erb params[:dashboard].to_sym
end
get '/views/:widget?.html' do
protected!
widget = params[:widget]
send_file File.join(settings.widget_path, widget, "#{widget}.html")
end
post '/widgets/:id' do
request.body.rewind
body = JSON.parse(request.body.read)
auth_token = body.delete("auth_token")
if !settings.auth_token || settings.auth_token == auth_token
Dashing::Application.send_event(params['id'], body)
204 # response without entity body
else
status 401
"Invalid API key\n"
end
end
class << self
def development?
ENV['RACK_ENV'] == 'development'
end
def production?
ENV['RACK_ENV'] == 'production'
end
def send_event(id, body)
body["id"] = id
body["updatedAt"] = Time.now.to_i
event = format_event(body.to_json)
settings.history[id] = event
settings.connections.each { |out| out << event }
end
def format_event(body)
"data: #{body}\n\n"
end
end
def latest_events
settings.history.inject("") do |str, (id, body)|
str << body
end
end
def first_dashboard
files = Dir[File.join(settings.views, '*.erb')].collect { |f| f.match(/(\w*).erb/)[1] }
files -= ['layout']
files.first
end
Dir[File.join(settings.root, 'lib', '**', '*.rb')].each {|file| require file }
{}.to_json # Forces your json codec to initialize (in the event that it is lazily loaded). Does this before job threads start.
job_path = ENV["JOB_PATH"] || 'jobs'
files = Dir[File.join(settings.root, job_path, '/*.rb')]
files.each { |job| require(job) }
end
end
Rails unable to execute /events root in this.
Can any one suggest me. How to call this /events root in rails.I am using batman.js to call events.
You might want to take a look at Dashing-Rails gem
it only applies on rails 4
Requirements
Ruby >=1.9.3
Rails 4
Redis
Multi Threaded server (puma, rainbows)

include file ruby selenium

I have multiple ruby test cases for selenium-webdriver and all the files are sharing the same functions. is there any way to create a global file and include the file to these test cases instead of typing them over and over again
for example - I create a file setup.rb
def setup
#driver = Selenium::WebDriver.for :firefox
wait = Selenium::WebDriver::Wait.new(:timeout => 10)
end
then in my test_file.rb I start
require setup
setup
#driver.find_element(:xpath => '//span[text()="войти"]').click
There is an error
NoMethodError:
undefined method `find_element' for nil:NilClass
Change it to a global variable from an instance variable. Make it $driver instead of #driver and you shouldn't have a problem. Change it to something like..
def self_setup
$driver = Selenium::WebDriver.for :firefox
wait = Selenium::WebDriver::Wait.new(:timeout => 10)
end
and then
require "./setup.rb"
setup.setup
$driver.find_element(:xpath => '//span[text()="войти"]').click
That should work. You'd probably want to go to a page first before you look for that xpath though. setup will only open up a new instance of firefox webdriver. Also I would suggest changing the name of setup.rb so it can be foo.setup insead of setup.setup. I use Lib.rb for the methods I want to be able to call regularly so for instance one would be Lib.signin_admin
Hope this works for you.
In response to your example, I think you forgot to include the setup module (you did put your method definition inside a module, right?). Also, the comment that mentions assigning the driver as a global variable (by naming it with a starting dollar sign) is a good idea. So things would look like this...
setup.rb
module Setup
def setup
$driver = Selenium::WebDriver.for :firefox
$wait = Selenium::WebDriver::Wait.new(:timeout => 10)
end
end
test_file.rb
require 'setup'
class SeleniumTest < Test::Unit::TestCase
include Setup # Modules need to be included (mixed-in) in order to be used inside classes
# Setup is automagically called when using TestUnit
$driver.get "http://www.yoururl.com"
$driver.find_element(:xpath => '//span[text()="войти"]').click
end
The downside is that for each new module and file you create, you have to require and include all of the new files and modules you want to use.
The method that I have found to work for me is to create a 'test_helper.rb', and to use a gem called 'require_all' that requires and includes all of the files from the directories you specify.
My test_helper.rb looks something like this:
require "rubygems"
require "require_all"
require "selenium-webdriver"
require "test-unit"
require_all relative_path("../lib/selenium/")
module TestHelpers
include Selenium
def setup
$driver = Selenium::WebDriver.for :firefox
...
end
def teardown
$driver.quit
end
end
And the test_page.rb only requires two lines:
# Line 1: Ensures the test_helper.rb gets loaded from the same directory the test_page.rb resides in
require File.join(File.dirname(__FILE__), 'test_helper')
class TestPage < Test::Unit::TestCase
# Line 2: Module needs mixed in to use its methods
include TestHelpers
def test_page
$driver.get "http://www.mysite.com"
assert $driver.find_element(:css => "div#my_site_logo")
end
end

How generate pdf in rake task using cron job rails 3

Hi i am using rails 3 and wicked pdf gem to generate pdf in my controllers.But now i want to
generate pdf in rake task which will run through cron jobs.After creating this PDF i will send
it in email.
this is my normal controller method to generate pdf
def generate_invoice_pdf
begin
#trunk_groups_orig = TrunkGroupSubscriber.all
render :pdf => "GenerateInvoice", :layout => false, :template => "/accountings/generate_invoice_pdf"
rescue => client
puts client.inspect
end
end
But how i can generate pdf in rake task
Many many thanks for any help
If you are using pdfkit or wicked_pdf then you can try this,see if it works.
Updating code
class PdfInvoice
def generate_invoice
#trunk_groups_orig = TrunkGroupSubscriber.all
content = File.read('#{Rails.root}/app/views/accountings/generate_invoice_pdf.erb')
template = ERB.new(content)
# THis will generate html content
html_content = template.result(binding)
# now you have html content
pdf= WickedPdf.new.pdf_from_string(html_content)
# then save to a file
save_path = Rails.root.join('pdfs','filename.pdf')
File.open(save_path, 'wb') do |file|
file << pdf
end
end
end
PdfInvoice.new.generate_pdf
#You can customize method based on your requirement,

Resources