How to use RuboCop::Cop::Rails::ApplicationRecord on Rails 4 - ruby-on-rails-4

I want to use ApplicationRecord Cop on Rails 4.
I already added 'self.abstract_class = true' .
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
end
And this file is written 'minimum_target_rails_version 5.0'.
https://github.com/rubocop-hq/rubocop-rails/blob/master/lib/rubocop/cop/rails/application_record.rb
So I created custom_cop like this.
# frozen_string_literal: true
module CustomCops
# #example
#
# # good
# class Rails5Model < ApplicationRecord
# # ...
# end
#
# # bad
# class Rails4Model < ActiveRecord::Base
# # ...
# end
class MustApplicationRecord < RuboCop::Cop::Cop
MSG = 'Models should subclass `ApplicationRecord`.'
SUPERCLASS = 'ApplicationRecord'
BASE_PATTERN = '(const (const nil? :ActiveRecord) :Base)'
include RuboCop::Cop::EnforceSuperclass
def autocorrect(node)
lambda do |corrector|
corrector.replace(node.source_range, self.class::SUPERCLASS)
end
end
end
end
But I got an error running rspec, like this.
Failure/Error:
class MustApplicationRecord < RuboCop::Cop::Cop
MSG = 'Models should subclass `ApplicationRecord`.'
SUPERCLASS = 'ApplicationRecord'
BASE_PATTERN = '(const (const nil? :ActiveRecord) :Base)'
include RuboCop::Cop::EnforceSuperclass
def autocorrect(node)
lambda do |corrector|
corrector.replace(node.source_range, self.class::SUPERCLASS)
NameError:
uninitialized constant CustomCops::RuboCop
Do you know how to solve this error, or other method( like override 'minimum_target_rails_version 5.0' to 'minimum_target_rails_version 4.0' ) ?
versions
Rails 4.2.8
ruby 2.6.6
rubocop 0.80.1
RSpec 3.9

The error is telling you that RuboCop is not defined.
You need to require 'rubocop' somewhere before you define your cop.

Related

undefined method `build' for #<RSpec::ExampleGroups::UserName:>

Im currently working on a Rails 4.2.6 and with RSpec 3.7 version. When I run my test I get the following error:
undefined method `build' for #<RSpec::ExampleGroups::UserName:0x007ff984a99d38>
What is triggering this error is the following code.
require 'rails_helper'
RSpec.describe User, "name" do
#setup
it "returns the email" do
#build
user = build(:user, email: "everlastingwardrobe#example.com")
# excercise and verify
expect(user.email).to eq "everlastingwardrobe#example.com"
end
end
I'm using build instead of create because I dont want to persist data into the database. I am however using factory_bot_rails so I should have access to this method.
Here is my Gemfile:
group :development, :test do
gem 'rspec'
gem 'rspec-rails'
gem 'factory_bot_rails'
gem 'byebug'
gem 'pry'
gem 'pry-nav'
gem 'pry-stack_explorer'
end
group :test do
gem "capybara"
gem "selenium-webdriver"
end
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 'spec_helper'
require "rspec/rails"
require "capybara/rspec"
# Prevent database truncation if the environment is production
abort("The Rails environment is running in production mode!") if Rails.env.production?
# Add additional requires below this line. Rails is not loaded until this point!
# Requires supporting ruby files with custom matchers and macros, etc, in
# spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are
# run as spec files by default. This means that files in spec/support that end
# in _spec.rb will both be required and run as specs, causing the specs to be
# run twice. It is recommended that you do not name files matching this glob to
# end with _spec.rb. You can configure this pattern with the --pattern
# option on the command line or in ~/.rspec, .rspec or `.rspec-local`.
#
# The following line is provided for convenience purposes. It has the downside
# of increasing the boot-up time by auto-requiring all files in the support
# directory. Alternatively, in the individual `*_spec.rb` files, manually
# require only the support files necessary.
#
# Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }
# Checks for pending migrations and applies them before tests are run.
# If you are not using ActiveRecord, you can remove this line.
ActiveRecord::Migration.maintain_test_schema!
Capybara.register_driver :selenium_chrome do |app|
Capybara::Selenium::Driver.new(app, browser: :chrome)
end
Capybara.javascript_driver = :selenium_chrome
RSpec.configure do |config|
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
config.fixture_path = "#{::Rails.root}/spec/fixtures"
# If you're not using ActiveRecord, or you'd prefer not to run each of your
# examples within a transaction, remove the following line or assign false
# instead of true.
config.use_transactional_fixtures = false
# RSpec Rails can automatically mix in different behaviours to your tests
# based on their file location, for example enabling you to call `get` and
# `post` in specs under `spec/controllers`.
#
# You can disable this behaviour by removing the line below, and instead
# explicitly tag your specs with their type, e.g.:
#
# RSpec.describe UsersController, :type => :controller do
# # ...
# end
#
# The different available types are documented in the features, such as in
# https://relishapp.com/rspec/rspec-rails/docs
config.infer_spec_type_from_file_location!
# Filter lines from Rails gems in backtraces.
config.filter_rails_from_backtrace!
# arbitrary gems may also be filtered via:
# config.filter_gems_from_backtrace("gem name")
# config.before(:suite) do
# DatabaseCleaner.clean_with(:truncation)
# end
#
# config.before(:each) do
# DatabaseCleaner.strategy = :transaction
# end
#
# config.before(:each, js: true) do
# DatabaseCleaner.strategy = :truncation
# end
#
# # This block must be here, do not combine with the other `before(:each)` block.
# # This makes it so Capybara can see the database.
# config.before(:each) do
# DatabaseCleaner.start
# end
#
# config.after(:each) do
# DatabaseCleaner.clean
# end
end
How can I fix this issue, or should I use create instead?
After adding the gem
Create file in spec/support/factory_bot.rb
Add to factory_bot.rb
RSpec.configure do |config|
config.include FactoryBot::Syntax::Methods
end
Add on rails_helper.rb
require 'support/factory_bot'
The build method is part of FactoryGirl or FactoryBot namespace
Why don't you try
FactoryBot.build(:user :email => 'everlastingwardrobe#example.com')

Block dotfiles in carrierwave

I want to allow uploading (all possible) image files through a carrierwave uploader.
Unfortunately it's possible that dotfiles such as .DS_STORE might get passed to the uploader. I tried adding an explicit whitelist to only allow image-formats that I know of, but that didn't help.
def extension_whitelist
%w(jpg jpeg gif png)
end
Also tried running all the files through a regexp and only allow matches
def extension_whitelist
[/^[^\.].*$/]
end
This also did not work.
Adding a blacklist was no help either
def extension_blacklist
%w(.ds_store .DS_STORE ds_store DS_STORE)
end
Here's my model
class LocalImage < ActiveRecord::Base
mount_uploader :image_file, ImageUploader
process_in_background :image_file
validates_integrity_of :image_file
end
Here's the uploader in question
class ImageUploader < CarrierWave::Uploader::Base
include CarrierWave::MiniMagick
include ::CarrierWave::Backgrounder::Delay
storage :file
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
end
I added the backlist/whitelist definitions and tested them all through (had the server restarted in between to ensure no caching issues). Also tested through the console but the model is always valid and does not throw an error upon create!ing.
path = "path_to_file/.DS_STORE"
File.exists?(path) # => true
local_image = LocalImage.new(image_file: File.open(path, 'rb'))
local_image.valid? # => true
local_image.save! # => true
LocalImage.create!(image_file: File.open(path, 'rb'))
# => <LocalImage id: 22325, code: nil, image_id: nil, image_file: ".DS_STORE", created_at: "2018-02-02 11:19:25", updated_at: "2018-02-02 11:19:25", import_filename: ".ds_store">
Running
Rails 4.2.0
Carrierwave 0.10.0
carrierwave_backgrounder 0.4.2
mini_magick 4.4.0
As stated here the method extension_whitelist only existed from version 0.11 on, so the version I am using didn't have this change yet.
I could fix the validation by either upgrading carrierwave to 0.11 or renaming my extension_whitelist to extension_white_list. (Same with blacklist -> black_list).

Getting syntax error: expecting token 'EOF', not 'end' and can't figure out why

So, I am trying to implement a way to add database migrations without an ORM/ODM for my SQLite3 database, and the error I'm getting (syntax error: expecting token 'EOF', not 'end') is for this code:
src/project/database/migration/migrations/1.cr:
require "../migration"
module Project
ver = 1
migration = Migration.new ver
migration.register_up |db| do
db.exec "create table version (version int)"
db.exec "insert into version values (?)", ver
end
migration.register_down |db| do
db.exec "drop table version"
end
Migrations[ver] = migration
end
I can't see any immediate issues with the syntax. This file imports the following file because it needs the class and the line Migrations = [] of Migration:
src/project/database/migration/migration.cr:
require "db"
require "sqlite3"
module Project
Migrations = [] of Migration
class Migration
def initialize(#version : Int)
end
# Registers a callback that will be called when the `up`-method is called.
# The callback must return either `true` for a successful migration,
# or `false` for a failed migration. If an `up` migration has
# failed, the `down` migration will be called to restore the database
# back to its previous state.
# The callback will receive an instance of `DB::Database`
#
# Example:
#
# ```
# migration = Migration.new(1)
#
# migration.register_up |db| do
# # Advance migration
# end
#
# migration.register_down |db| do
# # Recede migration
# end
# ```
def register_up(&block : (DB::Database) -> Bool)
#up = block
end
# Registers a callback that will be called when the `down`-method is called.
# See the `register_up` method for more information
def register_down(&block : (DB::Database) -> Bool)
#down = block
end
# Advances DB to the next version
def up(conn : DB::Database)
result = #up.call(conn)
unless result
# Failed migration, rollback
#down.call(conn)
raise Exception.new(`Failed to migrate database to version: #{#version}. Rolling back.`)
end
end
# Recedes DB to the previous version
def down(conn : DB::Database)
result = #down.call(conn)
unless result
# Failed migration, rollback
#up.call(conn)
raise Exception.new(`Failed to migrate database to version: #{#version - 1}. Rolling back.`)
end
end
end
end
Any ideas?
Syntax mistake is here:
migration.register_up |db| do
# ...
end
Should be:
migration.register_up do |db|
# ...
end
And the same in register_down.
See "Yield arguments" section in Blocks and Procs.

Rails: changing from development to production leads to NameError uninitialized constant

My application works in dev environment (WEBrick 1.3.1) on my mac laptop. I deployed it via capistrano onto a Ubuntu server running nginx & passenger and suddenly I am getting
NameError in SmsController#send_text_message: uninitialized constant
SmsController::PhoneNumber
. Here is a screenshot:
Apparently, the PhoneNumber class (app/models/phone_number.rb) is not being recognized. Here is the code for that class:
class PhoneNumber
include ActiveModel::Validations
include ActiveModel::Conversion
extend ActiveModel::Naming
attr_accessor :pnumber
validates :pnumber, presence: true
validates :pnumber, numericality: true
def initialize(attributes = {})
attributes.each do |name, value|
send("#{name}=", value)
end
end
def persisted?
false
end
end
Here is the code for the controller where the error is raised:
class SmsController < ApplicationController
def send_text_message
phone = PhoneNumber.new(pnumber: params[:phone])
logger.info "phone as submitted by the webform (params[:phone]) = " + params[:phone]
if phone.valid?
# code that sends a sms message..
flash[:success] = "Message has been sent!"
redirect_to :back
else
flash[:warning] = "This is not a valid mobile number"
redirect_to :back
end
end
end
What do I need to do to make this work in production?
==EDIT: I ran it locally on my mac under the production environment using the same stack (nginx, passenger) and I am not getting the error message. So it seems it must be something specific to the installation on my Ubuntu VPS. I re-started nginx but it did not change anything. I am really stumped - in theory this quirk should not happen.
==EDIT2: As requested by #rossta here is the content of config/application.rb:
require File.expand_path('../boot', __FILE__)
# Pick the frameworks you want:
require "active_record/railtie"
require "action_controller/railtie"
require "action_mailer/railtie"
require "sprockets/railtie"
# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)
module Appmate
class Application < Rails::Application
# Settings in config/environments/* take precedence over those specified here.
# Application configuration should go into files in config/initializers
# -- all .rb files in that directory are automatically loaded.
end
end
And here is the content of config/environments/production.rb:
Appmate::Application.configure do
config.cache_classes = true a
config.eager_load = true
# Full error reports are disabled and caching is turned on.
config.consider_all_requests_local = true # changed to help with debugging, TODO: change back to false once in production
config.action_controller.perform_caching = true
# Enable Rack::Cache to put a simple HTTP cache in front of your application
# Add `rack-cache` to your Gemfile before enabling this.
# For large-scale production use, consider using a caching reverse proxy like nginx, varnish or squid.
# config.action_dispatch.rack_cache = true
# Disable Rails's static asset server (Apache or nginx will already do this).
config.serve_static_assets = false
# Compress JavaScripts and CSS.
config.assets.js_compressor = :uglifier
# config.assets.css_compressor = :sass
# Do not fallback to assets pipeline if a precompiled asset is missed.
config.assets.compile = false
# Generate digests for assets URLs.
config.assets.digest = true
# Version of your assets, change this if you want to expire all your assets.
config.assets.version = '1.0'
config.log_level = :info
config.i18n.fallbacks = true
# Send deprecation notices to registered listeners.
config.active_support.deprecation = :notify
# Disable automatic flushing of the log to improve performance.
# config.autoflush_log = false
# Use default logging formatter so that PID and timestamp are not suppressed.
config.log_formatter = ::Logger::Formatter.new
end
I found the culprit - I seem to have not committed to my git repository the controller and the model files. So everything was working apart from that bit. Duh!
#rossta: thanks for helping! That stray 'a' is something that I must have added while copying the code into the SO post but your question made me look into my git repository - and this is how I found the changed but uncommitted files.

How can I use Sinatra to simulate a remote server in RSpec / VCR?

The VCR Cucumber documents show many examples using a tiny Sinatra app to simulate a remote server, using a function called start_sinatra_app loaded from vcr_cucumber_helpers.rb.
I'd like use something like that for my Rails / RSpec / VCR testing, but haven't figured out how to get start_sinatra_app (or equivalent) into my testing framework. My naive approach doesn't work since -- not surprisingly -- it can't find vcr_cucumber_helpers.rb.
What do I need to add to the following to make it work under RSpec? Or am I off in the weeds and doing this all wrong?
# file: spec/app/models/sinatra_test_spec.rb
require 'spec_helper'
start_sinatra_app(:port => 7777) do
get("/") { "Hello" }
end
describe "sinatra rspec test" do
it 'calls the sinatra app' do
VCR.use_cassette("sinatra_rspec_test") do
res = Net::HTTP.get_response('localhost', "/", 7777)
res.body.should == 'Hello'
end
end
end
Here's the code you're looking for:
def start_sinatra_app(options, &block)
raise ArgumentError.new("You must pass a port") unless options[:port]
require 'sinatra'
require 'support/vcr_localhost_server'
klass = Class.new(Sinatra::Base)
klass.disable :protection
klass.class_eval(&block)
VCR::LocalhostServer.new(klass.new, options[:port])
end
That in turn uses VCR::LocalhostServer:
require 'rack'
require 'rack/handler/webrick'
require 'net/http'
# The code for this is inspired by Capybara's server:
# http://github.com/jnicklas/capybara/blob/0.3.9/lib/capybara/server.rb
module VCR
class LocalhostServer
READY_MESSAGE = "VCR server ready"
class Identify
def initialize(app)
#app = app
end
def call(env)
if env["PATH_INFO"] == "/__identify__"
[200, {}, [VCR::LocalhostServer::READY_MESSAGE]]
else
#app.call(env)
end
end
end
attr_reader :port
def initialize(rack_app, port = nil)
#port = port || find_available_port
#rack_app = rack_app
concurrently { boot }
wait_until(10, "Boot failed.") { booted? }
end
private
def find_available_port
server = TCPServer.new('127.0.0.1', 0)
server.addr[1]
ensure
server.close if server
end
def boot
# Use WEBrick since it's part of the ruby standard library and is available on all ruby interpreters.
options = { :Port => port }
options.merge!(:AccessLog => [], :Logger => WEBrick::BasicLog.new(StringIO.new)) unless ENV['VERBOSE_SERVER']
Rack::Handler::WEBrick.run(Identify.new(#rack_app), options)
end
def booted?
res = ::Net::HTTP.get_response("localhost", '/__identify__', port)
if res.is_a?(::Net::HTTPSuccess) or res.is_a?(::Net::HTTPRedirection)
return res.body == READY_MESSAGE
end
rescue Errno::ECONNREFUSED, Errno::EBADF
return false
end
def concurrently
# JRuby doesn't support forking.
# Rubinius does, but there's a weird issue with the booted? check not working,
# so we're just using a thread for now.
Thread.new { yield }
end
def wait_until(timeout, error_message, &block)
start_time = Time.now
while true
return if yield
raise TimeoutError.new(error_message) if (Time.now - start_time) > timeout
sleep(0.05)
end
end
end
end
Webmock does this quite nicely.
Allow connections to localhost:
# spec/spec_helper.rb
require 'webmock/rspec'
WebMock.disable_net_connect!(allow_localhost: true)
And then point your URL to the app:
# spec/spec_helper.rb
RSpec.configure do |config|
config.before(:each) do
stub_request(:any, /api.github.com/).to_rack(SinatraApp)
end
end
For a clearer example, see:
http://robots.thoughtbot.com/how-to-stub-external-services-in-tests