I have a class Company that include GrowthRate.
models/company.rb
class Company < ActiveRecord::Base
include GrowthRate
end
In the growth_rate.rb, I add some methods for Array.
models/company/growth_rate.rb
module Company::GrowthRate
extend ActiveSupport::Concern
end
module Company::GrowthRate::Array
def growth_rate
# calculate growth rate
end
end
class Array
include Company::GrowthRate::Array
end
And I want to test the method of Array by MiniTest.
test/models/company/growth_rate_test.rb
require 'test_helper'
class CompanyTest < ActiveSupport::TestCase
include Company::GrowthRate
test 'test for adjusted_growth_rate' do
array = [1, 0.9]
Array.stub :growth_rate, 1 do
# assert_equal
end
end
end
But the test ends up with a name error.
NameError: undefined method `growth_rate' for `Company::GrowthRate::Array'
How can I include the method for MiniTest?
test/test_helper.rb
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__)
require 'rails/test_help'
require 'minitest/mock'
class ActiveSupport::TestCase
# Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
fixtures :all
end
You'll want to use the ActiveSupport included block.
For your example, I imagine it can't find the method b/c you're not requiring that file anywhere.
module PolymorphicTest
extend ActiveSupport::Concern
included do
test 'some cool polymorphic test' do
assert private_helper_method
end
private
def private_helper_method
# do stuff
end
end
end
Minitest also doesn't autoload these, so you'll need to make sure they're included in a require in each test or in the test_helper.
If you need me to break this down more, please ask.
I think you have to move the models/company/growth_rate.rb into app/model/concerns folder with filename = 'growth_rate.rb'
then don't use Company class to prevent conflict class name
module GrowthRate
extend ActiveSupport::Concern
# ...
end
Now you can include it to your Company model
then create array.rb file in the config/initializers folder which contains
class Array
def growth_rate
# calculate growth rate
end
end
this file will loaded only once by rails, it's good to adding custom method to Array class if you want to
now you can remove include Company::GrowthRate from test/models/company/growth_rate_test.rb
Related
How can I use stub method in setup?
I only found the stub with block like this:
class FooTest < ActiveSupport::TestCase
test 'for_something' do
Foo.stub :some_method, 3 do
#assert_equal
end
end
end
But I want to stub for all tests. How can I stub it?
You can achieve that by overriding #run method in your test case:
class FooTest < ActiveSupport::TestCase
def run
Foo.stub :some_method, 3 do
super
end
end
test 'for_something' do
#assert_equal
end
end
It's a common way to introduce the code that needs to be executed "around" every test case.
I think this already answered here - https://stackoverflow.com/a/39081919/3102718
With gem mocha you can stub methods in setup or in test, e.g.:
require 'active_support'
require 'minitest/autorun'
require 'mocha/mini_test'
module Foo
end
class FooTest < ActiveSupport::TestCase
setup do
Foo.stubs(:some_method).returns(300)
end
test 'for_something' do
assert Foo.some_method == 300
end
end
I have this in config/initializers/my_app_model.rb
module MyAppModel
def test
'test'
end
end
ActiveRecord::Base.send :include, MyAppModel
And in app/models/namespace/my_model.rb
class Namespace::MyModel < Namespace
def test
'changed!'
end
end
How can I make test to return changed!? It currently returns test.
From some posts I read, Rails loads models as they are asked, what I did was to make sure that model file was loaded just after initializer:
module MyAppModel
def test
'test'
end
end
ActiveRecord::Base.send :include, MyAppModel
require Rails.root.join 'app/models/namespace/my_model'
I want to include a module in a rails helper(is also a module).
The helper is:
module SportHelper
.....
end
And the module is:
module Formula
def say()
....
end
end
Now, I want to use the method say in SportHelper. What should I do?
If I write like this:
module SportHelper
def speak1()
require 'formula'
extend Formula
say()
end
def speak2()
require 'formula'
extend Formula
say()
end
end
This will work, but I don't want to do so, I just want to add the methods on the helper module,not every methods.
You need just to include this module in your helper:
require 'formula'
module SportHelper
include Formula
def speak1
say
end
def speak2
say
end
end
Maybe you don't need this line require 'formula', if it's already in the load path. For check this you can inspect $LOAD_PATH variable. For more information see this answer.
Basic difference between extend and include is that include is for adding methods to an instance of a class and extend is for adding class methods.
module Foo
def foo
puts 'heyyyyoooo!'
end
end
class Bar
include Foo
end
Bar.new.foo # heyyyyoooo!
Bar.foo # NoMethodError: undefined method ‘foo’ for Bar:Class
class Baz
extend Foo
end
Baz.foo # heyyyyoooo!
Baz.new.foo # NoMethodError: undefined method ‘foo’ for #<Baz:0x1e708>
And if you use extend inside the object method, it will adding methods to an instance of a class, but they would be available only inside this one method.
I think directly include should work
module SportHelper
include SportHelper
.........
end
end
I tested like below:
module A
def test
puts "aaaa"
end
end
module B
include A
def test1
test
end
end
class C
include B
end
c = C.new()
c.test1 #=> aaaa
It should work.
I want to create a gem which adds some functionality to my models. How to define a custom keyword for a Mongoid model? E.g.:
class Book
include Mongoid::Document
has_my_awesome_functionality
end
If you have a gem called foobar you can put the following into your gem's initialiser, or in a separate file (usually called railtie.rb[, just make sure it's being loaded]):
require 'foobar'
require 'rails'
class FooBar
class Railtie < Rails::Railtie
config.before_initialize do
::Mongoid::Document.module_eval do
def self.included(base)
base.extend FooBar::MongoidExtension
end
end
end if defined?(Mongoid)
end
and your extension can look like this:
module Foobar::MongoidExtension
def has_my_awesome_functionality
# logic here
end
end
When I add the following block of code in environments.rb, ActiveRecord::Base extends the module in the development environment but not in the test environment.
require "active_record_patch"
ActiveRecord::Base.send(:extend, ModelExtensions)
The library file which contains the module is as follows:
module ModelExtensions
def human_name_for(attr_hash)
# do something
end
end
Loading ./script/server and ./script/console seems fine on the development environment. But on the test environment, the following error occurs:
/home/test/rails_app/vendor/rails/activerecord/lib/active_record/base.rb:1959:in `method_missing':NoMethodError: undefined method `human_name_for' for #<Class:0x4a8d33>
For the solution, I modified the module and included the module to ActiveRecord::Base on the lib file itself:
module HumanAttributes
module ClassMethods
def human_name_for(attr_hash)
unless attr_hash.nil?
##human_names = attr_hash
class << self
def human_attribute_name key
##human_names[key.to_sym] || super unless key.nil?
end
end
end
end
end
end
module ActiveRecord
class Base
extend HumanAttributes::ClassMethods
end
end
This makes human_name_for accessible by any class extending from ActiveRecord::Base on all environments.
Just remember to require the file on the top of model file.
This works for me.
module ModelExtensions
def human_name_for(attr_hash)
# do something
end
end
In environment.rb
include ModelExtensions
ActiveRecord.extend(ModelExtensions)
Then this works ArObject.human_name _for(:asd)