VCR re-recording cassette does not persist - ruby-on-rails-4

Thanks in advance - i'm recording a controller spec with vcr.
The problem:
The first time I run my spec, it records fine, then I delete my_spec_context_dir, re-run the spec, and no cassette is saved under the cassettes dir!
The gems:
gem 'rspec-rails', '~> 3.2.1'
gem 'webmock', '1.22.3', require: false
gem 'vcr'
gem 'capybara', '~> 2.4.3'
The spec:
#spec/controllers/my_spec.rb
require 'unit_spec_helper'
describe 'description' do
it 'example_name', :vcr do
#instance_var = table_record.attribute
get 'controller_action'
expect(response.status).to eq(200)
expect(response.content_type).to eq 'image/png'
table_record.delete
end
end
What i've tried:
So I look at my configs to make sure vcr should be recording each time its run:
#spec/unit_spec_helper.rb
require 'vcr'
if Rails.env.test?
VCR.configure do |c|
c.ignore_localhost = false
c.hook_into :webmock
c.cassette_library_dir = "spec/support/cassettes"
c.configure_rspec_metadata!
c.allow_http_connections_when_no_cassette = true
c.default_cassette_options = {
allow_playback_repeats: true,
serialize_with: :json,
record: :all,
match_requests_on: [:method, :uri, :headers]
}
c.debug_logger = File.open(Rails.root.join('log/vcr.log'), 'w')
end
end
allow_playback_repeats: true, record: :all - yep, I think thats what I want
Checking the vcr.log, I see that the cassette was recorded:
[Cassette: 'MyController/description/example_name'] Initialized with options: {:record=>:new_episodes, :match_requests_on=>[:method, :uri, :headers], :allow_unused_http_interactions=>true, :serialize_with=>:json, :persist_with=>:file_system, :allow_playback_repeats=>true}
spec/support/cassettes dir is still empty, so i'm clearing the cache before the test... Rails.cache.clear and re-running.
Refreshing the spec/support/cassettes directory, I see its still empty. What do you suppose is keeping the .yml from saving?

Looks to be an issue with RubyMine7 - after a few restarts, it works.

Related

Loading Rubywork Facets unto a Rails Application

I want to use a particular rubyworks facets unto a helper:
require 'core/facets/string/snakecase'
module GenericTableHelper
def generic_table_theadlink(head_title, order_parameter = head_title.snake_case )
render(:partial => 'common_partials/generic_table/theadlink', :locals => {:head_title => head_title,
:order_parameter => order_parameter})
end
end
I get the error:
No such file to load -- core/facets/string/snakecase
Checked gemfile:
gem 'facets'
How do I load Rubyworks Facets unto the Helper? and any other model/view/controller
I think the core is leading you astray.
require 'facets/string/snakecase`

Rails 4 and paperclip - Stop the :original style file upload to copy it from an S3 remote directory

I use Paperclip 4.0.2 and in my app to upload pictures.
So my Document model has an attached_file called attachment
The attachment has few styles, say :medium, :thumb, :facebook
In my model, I stop the styles processing, and I extracted it inside a background job.
class Document < ActiveRecord::Base
# stop paperclip styles generation
before_post_process
false
end
But the :original style file is still uploaded!
I would like to know if it's possible to stop this behavior and copy the file inside the :original/filename.jpg from a remote directory
My goal being to use a file that has been uploaded in a S3 /temp/ directory with jQuery File upload, and copy it to the directory where Paperclip needs it to generate the others styles.
Thank you in advance for your help!
New Answer:
paperclip attachments get uploaded in the flush_writes method which, for your purposes, is part of the Paperclip::Storage::S3 module. The line which is responsible for the uploading is:
s3_object(style).write(file, write_options)
So, by means of monkey_patch, you can change this to something like:
s3_object(style).write(file, write_options) unless style.to_s == "original" and #queued_for_write[:your_processed_style].present?
EDIT: this would be accomplished by creating the following file: config/initializers/decorators/paperclip.rb
Paperclip::Storage::S3.class_eval do
def flush_writes #:nodoc:
#queued_for_write.each do |style, file|
retries = 0
begin
log("saving #{path(style)}")
acl = #s3_permissions[style] || #s3_permissions[:default]
acl = acl.call(self, style) if acl.respond_to?(:call)
write_options = {
:content_type => file.content_type,
:acl => acl
}
# add storage class for this style if defined
storage_class = s3_storage_class(style)
write_options.merge!(:storage_class => storage_class) if storage_class
if #s3_server_side_encryption
write_options[:server_side_encryption] = #s3_server_side_encryption
end
style_specific_options = styles[style]
if style_specific_options
merge_s3_headers( style_specific_options[:s3_headers], #s3_headers, #s3_metadata) if style_specific_options[:s3_headers]
#s3_metadata.merge!(style_specific_options[:s3_metadata]) if style_specific_options[:s3_metadata]
end
write_options[:metadata] = #s3_metadata unless #s3_metadata.empty?
write_options.merge!(#s3_headers)
s3_object(style).write(file, write_options) unless style.to_s == "original" and #queued_for_write[:your_processed_style].present?
rescue AWS::S3::Errors::NoSuchBucket
create_bucket
retry
rescue AWS::S3::Errors::SlowDown
retries += 1
if retries <= 5
sleep((2 ** retries) * 0.5)
retry
else
raise
end
ensure
file.rewind
end
end
after_flush_writes # allows attachment to clean up temp files
#queued_for_write = {}
end
end
now the original does not get uploaded. You could then add some lines, like those of my origninal answer below, to your model if you wish to transfer the original to its appropriate final location if it was uploaded to s3 directly.
Original Answer:
perhaps something like this placed in your model executed with the after_create callback:
paperclip_file_path = "relative/final/destination/file.jpg"
s3.buckets[BUCKET_NAME].objects[paperclip_file_path].copy_from(relative/temp/location/file.jpg)
thanks to https://github.com/uberllama

Rpsec and Factory Girl not cooperating

I'm kind of pulling my hair out on this one. I'm trying to test using rspec and Factory Girl (Ubuntu 13.10 and Rails 4). It seems as if Rspec doesn't see any of the Factory Girl stuff. Here's my spec_helper.rb:
# This file is copied to spec/ when you run 'rails generate rspec:install'
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'factory_girl_rails'
require 'rspec/rails'
require 'rspec/autorun'
require 'capybara/rspec'
Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
ActiveRecord::Migration.check_pending! if defined?(ActiveRecord::Migration)
RSpec.configure do |config|
config.include FactoryGirl::Syntax::Methods
config.use_transactional_fixtures = true
config.infer_base_class_for_anonymous_controllers = false
config.order = "random"
config.color_enabled = true
config.tty = true
config.formatter = :documentation # :progress, :html, :textmate
end
factories.rb:
FactoryGirl.define do
factory :exercise do
name 'New Exercise'
time 3
reps 7
weight 12
weight_unit 'kg'
factory :aerobic_exercise do
name 'Jumping Jacks'
kind 'Cardio/Aerobic'
end
factory :bodyweight_exercise do
name 'Pushups'
kind 'Bodyweight'
end
factory :cardio_exercise do
name 'Jumping Jacks'
kind 'Cardio/Aerobic'
end
factory :lifting_exercise do
name 'BB Shoulder Presses'
kind 'Weight Lifting'
end
end
end
and my failing spec:
#require 'test/spec'
require 'spec_helper'
describe Exercise do
describe 'Exercise properly normalizes values' do
it 'has weight and weight unit if kind is Weight Lifting' do
let(:exercise) { FactoryGirl.create(:lifting_exercise) }
exercise.should be_weight
exercise.time.should be_nil
end
it 'has time but not weight etc. if kind is Cardio' do
let(:exercise) { FactoryGirl.create(:aerobic_exercise) }
exercise.should be_time
exercise.reps.should be_nil
end
end
end
When I run rspec I get this error:
Failure/Error: let(:exercise) { FactoryGirl.create(:lifting_exercise) }
NoMethodError:
undefined method `let' for # <RSpec::Core::ExampleGroup::Nested_1::Nested_1:0x007f2f013b3760>
HELP!(please)
the let method isn't from FactoryGirl, it's from Rspec, and the issue is that let should not be nested within the it, it's meant to be used outside of it.
Given the way that you've written it, I think you should just use a local variable like this:
describe Exercise do
describe 'Exercise properly normalizes values' do
it 'has weight and weight unit if kind is Weight Lifting' do
exercise = FactoryGirl.create(:lifting_exercise)
exercise.should be_weight
exercise.time.should be_nil
end
it 'has time but not weight etc. if kind is Cardio' do
exercise = FactoryGirl.create(:aerobic_exercise)
exercise.should be_time
exercise.reps.should be_nil
end
end
end
Also, given that you've included FactoryGirl::Syntax::Methods in your spec_helper you don't need to prefix everything with FactoryGirl, you can just call it like this:
exercise = create(:lifting_exercise)
I hope that helps!
-Chad
Your issue is not RSpec and FactoryGirl not playing well together.
let is not part of an example's method group. Notice you have the let inside the it block. This should work
#require 'test/spec'
require 'spec_helper'
describe Exercise do
describe 'Exercise properly normalizes values' do
context 'with a lifting exercise' do
let(:exercise) { FactoryGirl.create(:lifting_exercise) }
it 'has weight and weight unit if kind is Weight Lifting' do
exercise.should be_weight
exercise.time.should be_nil
end
end
context 'with an aerobic exercise' do
let(:exercise) { FactoryGirl.create(:aerobic_exercise) }
it 'has time but not weight etc. if kind is Cardio' do
exercise.should be_time
exercise.reps.should be_nil
end
end
end
end
NOTE context is just an alias for describe.

Where do I put generator configurations in Rails 4?

I want to define the following:
config.generators.stylesheets = false
config.generators.javascripts = false
config.generators.helper = false
But despite reading Ror's guide on the subject, I don't get where exactly the methods should go.
I think it belongs in config/application.rb:
module MyApp
class Application < Rails::Application
# Lots of stuff
# Generator configuration
config.generators do |g|
g.orm :active_record
g.template_engine :erb
g.test_framework :test_unit, fixture: false
g.stylesheets false
g.helper false
end
end
end

Font asset without digest in Ruby on Rails 4

I've got a problem with my font assets being served without digest in production.
As soon as I do rake assets:precompile I get:
5futurebit-webfont-c133dbefd9e1ca208741ed53c7396062.eot
I was trying to link it with font-face in scss with asset-url, asset-path, font-url and font-path but all of them end up outputting path:
/assets/5futurebit-webfont.eot
For now I'm copying assets from /app/assets/fonts straight to /public/assets/ but it doesn't feel like that's the way to do it.
I've been looking at a similar issue and am currently using the non-stupid-digest-assets gem: https://github.com/alexspeller/non-stupid-digest-assets
For more info on how you can use it, see here.
Correct use of non-stupid-digest-assets gem
Now that being said, the link provided by Chris (specifically, https://stackoverflow.com/a/17367264/291640) seems like it may accomplish the same as the gem without the gem itself. I know I need to look into it further.
Make sure you have the exact filename WITH extention name of the font in your font-url declaration like:
Correct:
#font-face{
font-family: 'Sawasdee';
src: font-url('Sawasdee.ttf') format('truetype');
}
Wrong:
#font-face{
font-family: 'Sewasdee';
src: font-url('Sewasdee') format('truetype');
}
My font folder:
fonts
|_ Sewasdee.ttf
|_ Otherfont.ttf
Here is our solution, that is based partially on what Sprocets does. It is working with Rails4. It automatically generates a nondigest version for all assets, that were listed in config.assets.precompile, after precompilation was done.
# lib/tasks/assets_nondigest.rake
require 'fileutils'
namespace "assets:precompile" do
desc "Create nondigest versions of defined assets"
task :nondigest => :environment do
sprocket_task = Sprockets::Rails::Task.new ::Rails.application
assets = ::Rails.application.config.assets.precompile
paths = sprocket_task.index.each_logical_path(assets).to_a +
assets.select { |asset| Pathname.new(asset).absolute? if asset.is_a?(String)}
paths.each do |path|
if asset = sprocket_task.index.find_asset(path)
copy_target = File.join(sprocket_task.output, asset.digest_path)
target = File.join(sprocket_task.output, asset.logical_path)
sprocket_task.logger.info "Writing #{target}"
asset.write_to target
asset.write_to "#{target}.gz" if asset.is_a?(Sprockets::BundledAsset)
end
end
end
end
Rake::Task['assets:precompile'].enhance do
Rake::Task['assets:precompile:nondigest'].invoke
end