faker and factory_girl troubles [duplicate] - ruby-on-rails

This question already has answers here:
Faker is producing duplicate data when used in factory_girl
(4 answers)
Closed 7 years ago.
Good day!
I'm trying to create random values when creating model in my tests. Using factory_girl and faker gems
as of my gemfile.lock
factory_girl_rails (4.5.0)
factory_girl (~> 4.5.0)
faker (1.6.1)
I define factory as follows
FactoryGirl.define do
factory :action do
name Faker::Internet.email
id Faker::Number.digit
ip Faker::Internet.ip_v4_address
old_value Faker::Number.number(7)
end
end
but in my tests when i try to create objects, they have the same attributes.
> create :logger
id: 17,
new_value: 3133860,
name: "fidel_murazik#gibson.biz",
ip: "118.247.64.189",
created_at: Tue, 02 Feb 2016 09:12:50 UTC +00:00,
updated_at: Tue, 02 Feb 2016 09:12:50 UTC +00:00>
and the second time
> create :logger
id: 18,
new_value: 3133860,
name: "fidel_murazik#gibson.biz",
ip: "118.247.64.189",
created_at: Tue, 02 Feb 2016 09:12:53 UTC +00:00,
updated_at: Tue, 02 Feb 2016 09:12:53 UTC +00:00>
One more time - I'm trying to get via Faker gem random valid attributes for factory_girl every time I create a new object.
Can you please help me with this problem?

You may use sequence to generate different data every time running:
FactoryGirl.define do
factory :action do
sequence(:name) { |n| "user_#{n}#factory.com" }
sequence(:id) { |n| Faker::Number.digit + n }
ip Faker::Internet.ip_v4_address
old_value Faker::Number.number(7)
end
end
Btw id will be generated automatically, feel free to remove id!

Related

Using Acts As Votable for multiple database tables with Rails 5

I have been using https://github.com/ryanto/acts_as_votable gem as a Save button for Posts. It has been all good so far. 👍
However now I created a separate scaffold (Articles) and wanted to add the same Save button. So users can save Posts and Articles, then view in their profiles.
Now I got problem as some Article records has same id as Post records. Plus how do I even display Saved records now as I dont know what id comes from Article or Post. 🤔
Is there any way to solve this with Acts As Votable Gem?
Thank you! 🙏
The current version (0.12.0) of acts_as_voteable does this out of the box. The Vote model has a column votable_type which can be a reference to multiple models.
#<ActsAsVotable::Vote:0x00007f9f6558a9b0
id: 4,
votable_type: "Post",
votable_id: 1,
voter_type: "User",
voter_id: 2,
vote_flag: true,
vote_scope: "save",
vote_weight: 1,
created_at: Mon, 31 Dec 2018 13:39:34 UTC +00:00,
updated_at: Mon, 31 Dec 2018 13:39:34 UTC +00:00>,
#<ActsAsVotable::Vote:0x00007f9f6558a4d8
id: 5,
votable_type: "Article",
votable_id: 3,
voter_type: "User",
voter_id: 2,
vote_flag: true,
vote_scope: "article",
vote_weight: 1,
created_at: Tue, 01 Jan 2019 15:15:27 UTC +00:00,
updated_at: Tue, 01 Jan 2019 15:15:27 UTC +00:00>
To display saved records you can use a scope like
#user.votes.for_type(Post)
#user.votes.for_type(Article)
I hope this answers your question.

is it possible to override built-in Ruby methods?

I am working on a problem where I have to pass an rpsec test. The problem is that the method is using the same name as a built in ruby method .count
given that I cannot change the rspec test, is it possible to override .count to behave differently? if not, is there a better way to get around this?
here is the rspec test I am trying to pass
subject = FinancialSummary.one_day(user: user, currency: :usd)
expect(subject.count(:deposit)).to eq(2)
my code:
class FinancialSummary
def self.one_day(user: user, currency: currency)
one_day_range = Date.today.beginning_of_day..Date.today.end_of_day
find_transaction(user.id, currency).where(created_at: one_day_range)
end
def self.find_transaction(user_id, currency)
Transaction.where(user_id: user_id,
amount_currency: currency.to_s.upcase
)
end
end
output:
[#<Transaction:0x00007f9b39c2e9b8
id: 1,
user_id: 1,
amount_cents: 1,
amount_currency: "USD",
category: "deposit",
created_at: Sat, 10 Mar 2018 18:46:53 UTC +00:00,
updated_at: Sat, 10 Mar 2018 18:46:53 UTC +00:00>,
#<Transaction:0x00007f9b3d0dbc38
id: 2,
user_id: 1,
amount_cents: 2000,
amount_currency: "USD",
category: "deposit",
created_at: Sat, 10 Mar 2018 18:47:43 UTC +00:00,
updated_at: Sat, 10 Mar 2018 18:47:43 UTC +00:00>,
#<Transaction:0x00007f9b3d0b3fa8
id: 7,
user_id: 1,
amount_cents: 1200,
amount_currency: "USD",
category: "withdraw",
created_at: Mon, 05 Mar 2018 02:22:42 UTC +00:00,
updated_at: Tue, 06 Mar 2018 18:48:20 UTC +00:00>]
it is printing out, what I believe to be the correct information, up until the test attempts to count the transactions by their category: 'deposit'. Then I get this error message:
ActiveRecord::StatementInvalid: SQLite3::SQLException: no such column: deposit: SELECT COUNT(deposit) FROM "transactions" WHERE "transactions"."user_id" = ? AND "transactions"."amount_currency" = ?
EDITED FOR MORE INFO
Some Assumptions Were Made in the Writing of this answer and modifications may be made based on updated specifications
Overriding count is a bad idea because others who view or use your code will have no idea that this is not the count they know and understand.
Instead consider creating a scope for this like
class FinancialSummary < ApplicationRecord
scope :one_day, ->(user:,currency:) { where(user: user, currency: currency) } #clearly already a scope
scope :transaction_type, ->(transaction_type:) { where(category: transaction_type) }
end
then the test becomes
subject = FinancialSummary.one_day(user: user, currency: :usd)
expect(subject.transaction_type(:deposit).count).to eq(2)
SQL now becomes:
SELECT COUNT(*)
FROM
"transactions"
WHERE
"transactions"."user_id" = ?
AND "transactions"."amount_currency" = "usd"
AND "transactions"."category" = "deposit"
Still very understandable and easy to read without the need to destroy the count method we clearly just used.
It's not clear what object the count message is being sent to because I don't know what FinancialSummary.one_day(user: user, currency: :usd) returns, but it seems like you are saying count is a method on whatever it returns, that you can't change. What does FinancialSummary.one_day(user: user, currency: :usd).class return?
Perhaps one solution would be to alias it on that object by adding alias_method :count, :account_count and then in your test calling expect(subject.account_count(:deposit)).to eq(2)
It would be easier if you could post the FinancialSummary#one_day method in your question.

How to correctly use Devise + Confirmable + fixtures

I'm using Devise + Confirmable for user authentication and Minitest + Capybara + fixtures for testing. I can make working logged in tests for users as long as I included some form of login (either with the helper login_as(#user) or going to the login page with Capybara) and the line#user.confirm before running.
How can I confirm users in the fixture itself though so I don't have to include this line every time.
Right now I have:
confirmed_at: Time.now
in the yml, but it doesn't seem to make a difference.
Here is a working sample test, if it's useful for illustration:
def setup
#user = users(:user)
end
test 'user should be redirected to profile edit on first login' do
#user.confirm
visit(new_user_session_path)
fill_in('user_email', :with => #user.email)
fill_in('user_password', :with => 'foobar')
click_button('Log in')
assert_current_path(edit_user_registration_path)
end
and the user fixture:
user:
email: test1#example.com
confirmed_at: Time.now
encrypted_password: <%= Devise::Encryptor.digest(User, 'foobar') %>
sign_in_count: 0
I updated my answer. The solution of the problem is found here. You need to configure it as in the guide and call the method user.confirm! inside the module ControllerMacros method def login_user
https://github.com/plataformatec/devise/wiki/How-To:-Test-controllers-with-Rails-3-and-4-(and-RSpec)#controller-specs
Open source github page of a complete Devise Rspec Project including testing
https://github.com/RailsApps/rails-devise/blob/master/spec/features/users/sign_in_spec.rb
you are trying to set
User.confirmed_at = Time.now
but confirmed_at has datetime datatype at least in my postegresql db, so this may depend on the db you are using.
confirmed_at: datetime
So this is the Time.now format
pry(main)> Time.now
=> 2017-03-14 11:14:06 +0100
While this is is the User.confirmed_at format
user.confirmed_at
=> Sun, 05 Mar 2017 15:05:03 UTC +00:00
So you should use a compatible format/variable, try to search the DateTime class for a compatible format that includes the UTC as DateTime.now returns:
[40] pry(main)> DateTime.now
=> Tue, 14 Mar 2017 11:19:25 +0100
DateTime has a utc() method. If I run this it is almost what is needed.
DateTime.civil(2005, 2, 21, 10, 11, 12, Rational(-6, 24)).utc
DateTime.civil(2005, 2, 21, 10, 11, 12, Rational(-6, 24)).utc
=> 2005-02-21 16:11:12 UTC
Check the DateTime api and if needed you can check the utc() method on github
DateTime.civil(2005, 2, 21, 10, 11, 12, Rational(-6, 24)) # => Mon, 21 Feb 2005 10:11:12 -0600
DateTime.civil(2005, 2, 21, 10, 11, 12, Rational(-6, 24)).utc # => Mon, 21 Feb 2005 16:11:12 UTC
# File activesupport/lib/active_support/core_ext/date_time/calculations.rb, line 168
def utc
utc = new_offset(0)
Time.utc(
utc.year, utc.month, utc.day,
utc.hour, utc.min, utc.sec + utc.sec_fraction
)
end
http://api.rubyonrails.org/classes/DateTime.html#method-i-utc

rspec - why does this assert_equal comparison test work on a mac and not on Ubuntu? [duplicate]

This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
rspec - why does this attribute comparison usng assert_equal fail when they are the same, on ubuntu only?
Ruby: 1.9.3-p194
Rails: 3.2.8
Ubuntu: 12.04
The test has a lot of setup and then eventually does:
assert_equal #iep_service.attributes, IepService.first.attributes
Works on a mac but fails on ubuntu with:
2) Iep Service Spreadsheet A typical district With pre-existing students And a pre-existing Iep Service for one of those students And an Iep S[52/427$
SV Prevent importing
Failure/Error: assert_equal #iep_service.attributes, IepService.first.attributes
MiniTest::Assertion:
<{"id"=>212,
"duration"=>30,
"frequency"=>3,
"period"=>"week",
"group_size"=>"group",
"location"=>nil,
"service"=>nil,
"area_of_need"=>"speech",
"created_at"=>Wed, 24 Oct 2012 18:59:47 UTC +00:00,
"updated_at"=>Wed, 24 Oct 2012 18:59:47 UTC +00:00,
"therapist_id"=>nil,
"start_date"=>nil,
"end_date"=>nil,
"student_id"=>233,
"adhoc"=>false}> expected but was
<{"id"=>212,
"duration"=>30,
"frequency"=>3,
"period"=>"week",
"group_size"=>"group",
"location"=>nil,
"service"=>nil,
"area_of_need"=>"speech",
"created_at"=>Wed, 24 Oct 2012 18:59:47 UTC +00:00,
"updated_at"=>Wed, 24 Oct 2012 18:59:47 UTC +00:00,
"therapist_id"=>nil,
"start_date"=>nil,
"end_date"=>nil,
"student_id"=>233,
"adhoc"=>false}>.
# (eval):2:in `assert_equal'
# ./spec/models/iep_service_spreadsheet_spec.rb:71:in `block (6 levels) in <top (required)>'
The full source, if it help, is:
context "A typical district" do
before(:each) { set_up_district }
context "With pre-existing students" do
before(:each) { StudentSpreadsheet.new(#district, open_spec_fixture_file('sample-students.csv')) }
context "And a pre-existing Iep Service for one of those students" do
before(:each) { #iep_service = FactoryGirl.create(:iep_service, :student => #district.students.first) }
context "And an Iep Service CSV" do
before(:each) { #spreadsheet = IepServiceSpreadsheet.new(#district, open_spec_fixture_file('sample-ieps.c sv')) }
specify "Prevent importing" do
# Leave database untouched
assert_equal 1, IepService.count
assert_equal #iep_service.attributes, IepService.first.attributes
# Provide error report
assert #spreadsheet.error_report.any?
end
end
end
end
end
assert_equal uses the operator/method ==.
You can read the documentation for assert_equal here: http://ruby-doc.org/core/classes/Test/Unit/Assertions.html#M006665. It comes directly from Ruby, Rails don't overrides the definition.
So depending on the object type the == bahaves differently, and also as it comes from Ruby there may be a different implementation or slightly difference in the ruby code.
Anyways, it is better for you to compare value by value or live with the == comparison may bring to you.

Most proper way to use inherited classes with shared relations?

I have the TestVisual class that is inherited by the Game class :
class TestVisual < Game
include MongoMapper::Document
end
class Game
include MongoMapper::Document
belongs_to :maestra
key :incorrect, Integer
key :correct, Integer
key :time_to_complete, Integer
key :maestra_id, ObjectId
timestamps!
end
As you can see it belongs to Maestra.
So I can do Maestra.first.games which returns []
But I can not to Maestra.first.test_visuals because it returns undefined method test_visuals
Since I'm working specifically with TestVisuals, that is ideally what I would like to pull, but still have it share the attributes of its parent Game class.
Is this possible with Mongo. If it isn't or if it isn't necessary, is there any other better way to reach the TestVisual object from Maestra and still have it inherit Game ?
Single Collection Inheritance (SCI) in MongoMapper auto-generates selection,
ex., the following produce the same results.
p Game.where(_type: 'TestVisual').all
p TestVisual.all
See also mongomapper/lib/mongo_mapper/plugins/sci.rb - MongoMapper::Plugins::Sci::ClassMethods#query
However, MongoMapper does not auto-generate associations for subclasses based on the base class' associations,
and I don't think that this should be expected.
Note that SCI places subclasses and base classes in the same MongoDB collection.
If this is not what you want, you should consider other mechanisms for modularity.
You can define the following method yourself for an association accessor method, perhaps this is sufficient for your purposes?
For other association methods like append or push, the parent methods are probably workable.
class Maestra
include MongoMapper::Document
key :name, String
many :games
def test_visuals
games.where(_type: 'TestVisual')
end
end
test/unit/test_visual_test.rb
require 'test_helper'
def ppp(obj)
puts obj.inspect.gsub(/, ([^#])/, ",\n\t\\1").gsub(/, #/, ",\n #")
end
class TestVisualTest < ActiveSupport::TestCase
def setup
Maestra.delete_all
Game.delete_all
end
test "inheritance" do
maestra = Maestra.create(name: 'Fiona')
maestra.games << Game.create(incorrect: 1, correct: 9, time_to_complete: 60)
maestra.games << TestVisual.create(incorrect: 2, correct: 8, time_to_complete: 61)
ppp maestra.games.to_a
ppp maestra.test_visuals.to_a
end
end
output
Run options: --name=test_inheritance
# Running tests:
[#<Game _id: BSON::ObjectId('4ff7029a7f11ba6e43000002'),
_type: "Game",
correct: 9,
created_at: Fri,
06 Jul 2012 15:22:02 UTC +00:00,
incorrect: 1,
maestra_id: BSON::ObjectId('4ff7029a7f11ba6e43000001'),
time_to_complete: 60,
updated_at: Fri,
06 Jul 2012 15:22:02 UTC +00:00>,
#<TestVisual _id: BSON::ObjectId('4ff7029a7f11ba6e43000003'),
_type: "TestVisual",
correct: 8,
created_at: Fri,
06 Jul 2012 15:22:02 UTC +00:00,
incorrect: 2,
maestra_id: BSON::ObjectId('4ff7029a7f11ba6e43000001'),
time_to_complete: 61,
updated_at: Fri,
06 Jul 2012 15:22:02 UTC +00:00>]
[#<TestVisual _id: BSON::ObjectId('4ff7029a7f11ba6e43000003'),
_type: "TestVisual",
correct: 8,
created_at: Fri,
06 Jul 2012 15:22:02 UTC +00:00,
incorrect: 2,
maestra_id: BSON::ObjectId('4ff7029a7f11ba6e43000001'),
time_to_complete: 61,
updated_at: Fri,
06 Jul 2012 15:22:02 UTC +00:00>]
.
Finished tests in 0.026661s, 37.5080 tests/s, 0.0000 assertions/s.
1 tests, 0 assertions, 0 failures, 0 errors, 0 skips

Resources