Carrierwave and rails fixtures - ruby-on-rails

How would I use populate rails fixtures(yaml) with carrierwave uploads?
The documentation doesn't seem to cover this and the carrierwave wiki does not either.
I have tried
and I have verified that the above ruby code generates a valid file object.

I doubt fixtures are going anywhere as they are used exclusively in the Rails codebase itself. Plus i use them, so that is all that matters.
I also found this article that helped me, and also you.
Boiled down in test_helper.rb
class ActiveSupport::TestCase
# Add more helper methods to be used by all tests here...
CarrierWave.root = Rails.root.join('test/fixtures/files') #path is up to you
def after_teardown
super
CarrierWave.clean_cached_files!(0)
end
end
class CarrierWave::Mount::Mounter
def store!
# Not storing uploads in the tests
end
end
I then put in my uploader:
def store_dir
if Rails.env.test?
"images"
else
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
end
I'm sure i can get rid of the need for that store_dir ternary like statement, but for now it works. I've got another way if this doesn't do work for you, but this is cleaner.

Related

How can I avoid a constant when I want a global object in rails?

I am want to add S3 file storage to my rails 5 application. Since I am using heroku I used their tutorial which says to just create a constant named S3_BUCKET in your config/initializers/aws.rb and you can use that constant everywhere.
The heroku code looks like this:
#config/initializers/aws.rb
S3_BUCKET = Aws::S3::Resource.new.bucket(ENV['S3_BUCKET'])
The problem with this is that I have to override this constant for the specs to work.
I have this alternative solution (which is sadly not working):
#lib/aws_helpers/s3.rb
module AWSHelpers
module S3
class << self
attr_accessor :configuration
def configure
self.configuration ||= Configuration.new
yield(configuration)
end
def bucket
#bucket ||= Aws::S3::Resource.new.bucket(configuration.s3_bucket)
end
end
class Configuration
attr_accessor :s3_bucket, :aws_access_key_id, :aws_secret_access_key_id
end
end
end
#config/initializers/aws.rb
AWSHelpers::S3.configure do |config|
config.s3_bucket = ENV['S3_BUCKET']
config.aws_access_key_id = ENV['AWS_ACCESS_KEY_ID']
config.aws_secret_access_key_id = ENV['AWS_SECRET_ACCESS_KEY']
end
What I want to be able to do in a controller is:
AWSHelpers::S3.bucket.object(a_key)
Unfortunately this fails and tells me that bucket method can't return anything because the configuration is nil.
What I know:
the aws initializer gets executed and when I add puts in all the methods I can see the correct output when my server starts via rails s
the controller knows about the service module or it would not even get to the bucket method
the code works when I dump the content of config/initializers/aws.rb into the controller
I really would like to know why the code above is not working. It seems to set up everything correctly and then when I want to use it in the controller suddenly things are as if i'd never called configure.
I am also open to other suggestions on how to do this. Just using the constant is not an option because it has to be changed for the specs to work.
This code might look strange, but it's actually exactly what you'd want in this situation. Keep in mind this situation is a bit irregular, it's for configuring a plugin that has external API dependencies and associated keys that must be populated before the rest of the code works.
It's ugly from an implementation perspective, but from a usability perspective it's nice. You can just do AWSHelpers::S3.configure do |config| as shown in the initializer. All that code is to make those semantics work properly.
This is a cheap trick, but it works.
in config/application.rb:
module YourApp
class Application < Rails::Application
def s3_bucket
#s3_bucket ||= begin
# your stuff
end
end
end
end
Rails.application.s3_bucket.object(a_key)

Safe and best way to monkey patch a rails gem

I have tried, seriously. Many questions out there but many developers say "It dont work for me"; I'm one of them -- said to say.
I was reading up on the best way to monkey-patch a rails gem. I've found few but decided to use this method.
I want to monkey-patch the xeroizer gem but rather the invoice.rb model.
# lib/xeroizer/invoice/invoice_url.rb
module Xeroizer
module Invoice
module InvoiceUrl
def invoice_url(id)
#application.http_get(#application.client, "#{url}/#{CGI.escape(id)}/OnlineInvoice")
end
end
end
end
Going with the "this method" link, I assume this should work, but it dosent.
Controller:
include Xeroizer::Invoice::InvoiceUrl
# Invoice.include Xeroizer::Invoice::InvoiceUrl
def some_method
# #xero is in a private method. It's here for short demonstration
#xero = Xeroizer::PrivateApplication.new("MY_CONSUMER_KEY", "MY_SECRET_KEY", "#{Rails.root}/privatekey.pem")
Rails.logger = #xero.Invoice.invoice_url("ad61ea97-b9e9-4a1e-b754-7c19e62f8cd7")
end
undefined method `invoice_url' for Xeroizer::Record::InvoiceModel
How do you add custom methods to a rails gem's class?
Assuming you are trying to monkey-patch Xeroizer::Record::InvoiceModel with Xeroizer::Invoice::InvoiceUrl, you might just do the following right after the first mention of Xeroizer::Record::InvoiceModel (to make Rails to autoload it):
Xeroizer::Record::InvoiceModel.prepend Xeroizer::Invoice::InvoiceUrl
This will override original invoice_url method. The original one still might be called from a prepended using super.

Patching Module in Ruby

I'm trying to add the following code that I found online as a workaround for a problem with combining MongoDB and Backbone.js in Rails, but I actually don't know Ruby/Rails that well because I'm learning all three at once.
Currently, I've just created a file in lib/ called mongoid.rb with the following content:
module Mongoid
module BackboneSerialization
extend ActiveSupport::Concern
module InstanceMethods
def serializable_hash(options = nil)
persisted? ? super.merge('id' => _id) : super
end
end
end
end
Assuming that this code is correct, is there anything else I have to be aware of to make this work. All I'm doing now is adding this code and then starting my server but that doesn't seem to solve the problem. Is there a specific place I need to store it- like lib/mongoid/backbone_serialization/instance_methods? Or do I need to include this in certain files? If so, do I include just Mongoid or submodules?
config/environment.rb,
after require File.expand_path('../application', __FILE__)
and before APPNAME::Application.initialize!
add require "mongoid"

Carrierwave store_dir not modified when running rspec with spork

I've followed the instructions on how to define a test-specific store directory for carrierwave uploads, which suggests opening the CarrierWave::Uploader::Base class and redefining store_dir and cache_dir like so:
if defined?(CarrierWave)
CarrierWave::Uploader::Base.descendants.each do |klass|
next if klass.anonymous?
klass.class_eval do
def cache_dir
"#{Rails.root}/spec/support/uploads/tmp"
end
def store_dir
"#{Rails.root}/spec/support/uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
end
end
end
This works like a charm, except when I run rspec with spork, then it fails to modify the class and uploads are stored in the default location. Does anyone have any clue why this might be happening?
Someone else working on our project solved this problem by adding a line with just AvatarUploader ahead of the CarrierWave::Uploader::Base.descendants.each line, like this:
if defined?(CarrierWave)
AvatarUploader # load AvatarUploader class
CarrierWave::Uploader::Base.descendants.each do |klass|
#...
Not entirely sure why this works, but it does.
Little addition to accepted answer, for anyone coming here:
if uploader classes are not loaded before the call to
CarrierWave::Uploader::Base.descendants, it will return empty array, so either specify each uploader like in accepted answer or you could do something like this to require all uploaders from let's say rails uploaders folder
Dir["#{Rails.root}/app/uploaders/*.rb"].each {|file| require file}
CarrierWave::Uploader::Base.descendants.each do |klass|
#...

Having trouble overriding storage directory using Carrierwave gem

I watched Railscast 253 and decided to use Carrierwave for my file uploading needs. I know I must be doing something very dumb, but I am neither successful in overriding the store_dir method nor the filename method in my uploader. The following is my code which nearly identical to Ryan Bates' code in the Railscast.
class DocumentUploader < CarrierWave::Uploader::Base
# some stuff here
# Override the directory where uploaded files will be stored.
# This is a sensible default for uploaders that are meant to be mounted:
def store_dir
"documents/#{model.class.to_s.underscore}/#{model.id}"
end
# more stuff here
def filename
"#{active_customer.last_name}_#{active_customer.first_name}_#{active_system.desc}.pdf" if original_filename
end
end
The uploaded files are instead being stored in public/uploads/tmp with some default file name. What could I be doing wrong here? Is there an important step in the Carrierwave set up that maybe Ryan Bates did not include in the Railscast?

Resources