How can I represent a character with an accent in FactoryGirl? - ruby-on-rails

I have the following factory which I'd like to use in conjunction with a FactoryGirl.create_list to produce a small dataset with some specific values:
FactoryGirl.define do
factory :name do
forename "Ziggy"
surname "Stardust"
factory :sequence_of_names do
sequence(:forename) do |n|
forenames = %w(Robert Tommy Tomi Rob Mohammad Amélie Zoo John Robert Brown)
"#{forenames[n-1]}"
end
sequence(:surname) do |n|
surnames = %w(Thingy Robert smyth Brown Adbul Zoo Cafe Robert Thingy)
"#{surnames[n-1]}"
end
end
end
end
The forename 'Amélie' has caused an issue:
syntax error, unexpected $end, expecting keyword_end ...rt Tommy Tomi
Rob Mohammad Amélie Zoo John Robert Brown)
In an rspec file I can simply add the following for the 'é' character to be supported:
# encoding: UTF-8
But this doesn't seem to work for a FactoryGirl file; and ideas?

Related

Field must only contain letters. How to do this with Rails ActiveRecord Validation?

I'm working with a rails app and the project required the firstname and lastname fields of the User model to only accept letters.
How do you do this in Rails ActiveRecord validation?
Just to expand on the conversation in the comments that's without an answer attached, the following should be what you're after:
LETTER_REGEX = /\A\p{L}+\Z/.freeze
validates :lastname, format: { with: LETTER_REGEX, message: "only allows letters" }
I'd recommend Regex101 if you're trialling different approaches. It lets you test input, and provides a good explanation of the regex. Here, for this example:
\A asserts position at start of the string
\p{L}+
matches any kind of letter from any language
+ Quantifier — Matches between one and unlimited times, as many times as possible, giving back as needed (greedy)
\z asserts position at the end of the string
Re \p, in this case it's taking a Unicode variant (all of which can be viewed here, and in far more detail here).
Hope that's useful - let me know how you get on or if you have any questions.
RTM: https://guides.rubyonrails.org/active_record_validations.html
Will be something like this
class User < ApplicationRecord
LETTER_ONLY_RE = /\A\p{Letter}+\z/
validates :lastname, format: { with: LETTER_ONLY_RE,
message: "only allows lowercase letters" }
# same for firstname
end

Use a factory's sequence to generate unique phone numbers

I'm new to TDD, RSpec and factories, and trying to understand how to test that each User's phone number attribute is unique. To do so, I'm trying to use a sequence in my User factory. I'm not having much luck with the following:
FactoryGirl.define do
factory :user do
number = 123456789
sequence(:phone_number) {|n| (number + n).to_s }
end
end
Any thoughts on the best way to accomplish this? Also, what kind of test would make sense for something like this where ultimately I would want to add the following validation to the user model to make such a test pass?
validates :phone_number, :uniqueness => true
Thanks!
Try using a lambda with a random 10 digit number:
phone_number { rand(10**9..10**10) }
Try this:
FactoryGirl.define do
sequence :phone_number do |n|
"123456789#{n}"
end
factory :user do
phone_number
end
end
and in order to test your validation use this in your user_spec
it { should validate_uniqueness_of(:phone_number) }
To complete #westonplatter answer, in order to start at 0 000 000 000, you can use String#rjust:
FactoryGirl.define do
factory :user do
sequence(:phone_number) {|n| n.to_s.rjust(10, '0') }
end
end
Example:
> 10.times { |n| puts n.to_s.rjust(10, '0') }
0000000000
0000000001
0000000002
0000000003
0000000004
0000000005
0000000006
0000000007
0000000008
0000000009
While the random solution works, you have a small chance of not getting a unique number. I think you should leverage the FactoryGirl sequence.
We can start at, 1,000,000,000 (100-000-000) and increment up. Note: This only gives you 98,999,999,999 unqiue phone numbers, which should be sufficient. If not, you have other issues.
FactoryGirl.define do
sequence :phone_number do |n|
num = 1*(10**8) + n
num.to_s
end
factory :user do
phone_number
end
end

Factory Girl: using sequence inline vs not inline

There are (at least?) two ways to use a sequence in factory girl:
Factory.sequence :my_id do |n|
"#{n}"
end
Factory.define :my_object do |mo|
mo.id Factory.next :my_id
end
and simply doing it inline:
Factory.define :my_object do |mo|
mo.sequence(:id) { |n| "#{n}" }
end
My question is this. If I use the inline version in two different factories, will there be two different sequences that both start at 1 and increment in tandem...meaning that if I create one of each type of factory object they will both have id 1?
If I use the externally defined sequence in two different factories am I guaranteed to get unique ids across the two objects? Meaning will the ids of each object be different?
I am trying to confirm if the behavior above is accurate because I'm working with a completely goofy data model trying to get rspec & factory girl to play nice with it. The designer of the database set things up so that different objects have to have ids generated that are unique across a set of unrelated objects. Changing the data model at this point is not a feasible solution though I'd really love to drag this stuff back onto the Rails.
When using externally defined sequences in two different factories you will see incrementing ids across the factories. However, when using inline sequences each factory will have their own sequence.
I created the example rake task below to illustrate this. It displays the following results:
*** External FactoryGirl Sequence Test Results ***
User Name: Name 1
User Name: Name 2
User Name: Name 3
User Name: Name 4
Role: Name 5
Role: Name 6
Role: Name 7
Role: Name 8
*** Internal FactoryGirl Sequence Test Results ***
User Name: Name 1
User Name: Name 2
User Name: Name 3
User Name: Name 4
Role: Role 1
Role: Role 2
Role: Role 3
Role: Role 4
As you can see, when using external sequences the number continues to increase as you move from the user to the role. However when using an inline sequence the increments are independent of each other.
The following schema files were used for this example:
create_table "users", :force => true do |t|
t.string "name"
t.string "email"
end
create_table "roles", :force => true do |t|
t.string "name"
end
The example rake task is:
require 'factory_girl_rails'
namespace :sequencetests do
Rake::Task[:environment].invoke
task :external do
FactoryGirl.factories.clear
desc "Factory Girl Sequence Test using an externally defined sequence"
puts "*** External FactoryGirl Sequence Test Results ***"
FactoryGirl.define do
sequence :name do |n|
"Name #{n}"
end
factory :user do |u|
name
end
factory :role do |r|
name
end
end
users = buildit(:user)
roles = buildit(:role)
puts( showit(users, "User Name: "))
puts( showit(roles, "Role: "))
end
task :inline do
FactoryGirl.factories.clear
puts "*** Internal FactoryGirl Sequence Test Results ***"
desc "Factory Girl Sequence Test using an inline sequence"
FactoryGirl.define do
factory :user do |u|
u.sequence(:name) {|n| "Name #{n}" }
end
factory :role do |r|
r.sequence(:name) {|n| "Role #{n}" }
end
end
users = buildit(:user)
roles = buildit(:role)
puts( showit(users, "User Name: "))
puts( showit(roles, "Role: "))
end
end
task sequencetests: ['sequencetests:external', 'sequencetests:inline']
def buildit(what)
items = []
4.times do
items << FactoryGirl.build(what)
end
items
end
def showit(items, prefix = "Name: ")
results = ""
items.each do |item|
results += "#{prefix}#{item.name}\n"
end
results
end
I hope this helps explain the different possibilities when using sequences in FactoryGirl.
Yes, the inline versions will create 2 independent sequences, each starting at 1

Regex to pull out postal code from string

I have a search string that a user inputs text into.
If it contains any part of a postal code like: 1N1 or 1N11N1 or 1N1 1N1 then I want to pull that out of the text.
example:
John Doe 1n11n1
or
1n1 John Doe
or
John 1n11n1 Doe
I want to capture this:
postal_code: 1n11n1
other: John Doe
Can this be done using regex?
Try matching the regular expression /((?:\d[A-Za-z]\d)+)/ and returning $1:
def get_postal_code(s)
r = /((?:\d[A-Za-z]\d)+)/
return (s =~ r) ? [$1, s.sub(r,'')] : nil
end
# Example usage...
get_postal_code('John Doe 1n11n1') # => ['1n11n1', 'John Doe ']
get_postal_code('1n1 John Doe') # => ['1n1', ' John Doe']
get_postal_code('John Doe 1n1') # => ['1n1', 'John Doe ']
You could also cleanup the "other" string as follows.
...
return (s =~ r) ? [$1, s.sub(r,'').gsub(/\s+/,' ').strip] : nil
end
get_postal_code('John Doe 1n11n1') # => ['1n11n1', 'John Doe']
get_postal_code('1n1 John Doe') # => ['1n1', 'John Doe']
get_postal_code('John Doe 1n1') # => ['1n1', 'John Doe']
Not sure what is the format of the postal codes where you are, but I'd definitely resort to regexlib:
http://regexlib.com/Search.aspx?k=postal%20code
You'll find many regular expressions that you can use to match the postal code in your string.
To get the rest of the string, you can simply do a regex remove on the postal code and get the resulting string. There is probably a more efficient way to do this, but I'm going for simplicity :)
Hope this helps!
Yes, this can be done using a regex. Depending on the type of data in the rows you may be at risk for false positives, because anything that matches the pattern will be seen as a postal code (in your example though that does not seem likely).
Assuming that in your patterns N is an alpha character and 1 a numeric character you'd do something like the below:
strings = ["John Doe 1n11n1", "1n1 John Doe", "John 1n1 1n1 Doe"]
regex = /([0-9]{1}[A-Za-z]{1}[0-9]{2}[A-Za-z]{1}[0-9]{1}|[0-9]{1}[A-Za-z]{1}[0-9]{1}\s[0-9]{1}[A-Za-z]{1}[0-9]{1}|[0-9]{1}[A-Za-z]{1}[0-9]{1})/
strings.each do |s|
if regex.match(s)
puts "postal_code: #{regex.match(s)[1]}"
puts "rest: #{s.gsub(regex, "")}"
puts
end
end
This outputs:
postal_code: 1n11n1
rest: John Doe
postal_code: 1n1
rest: John Doe
postal_code: 1n1 1n1
rest: John Doe
If you want to get rid of excess spaces you can use String#squeeze(" ") to make it so :)

Problem on Rails fixtures creation sequence

I am reading the book Simply Rails by Sitepoint and given these models:
story.rb
class Story < ActiveRecord::Base
validates_presence_of :name, :link
has_many :votes do
def latest
find :all, :order => 'id DESC', :limit => 3
end
end
def to_param
"#{id}-#{name.gsub(/\W/, '-').downcase}"
end
end
vote.rb
class Vote < ActiveRecord::Base
belongs_to :story
end
and given this fixtures
stories.yml
one:
name: MyString
link: MyString
two:
name: MyString2
link: MyString2
votes.yml
one:
story: one
two:
story: one
these tests fail:
story_test.rb
def test_should_have_a_votes_association
assert_equal [votes(:one),votes(:two)], stories(:one).votes
end
def test_should_return_highest_vote_id_first
assert_equal votes(:two), stories(:one).votes.latest.first
end
however, if I reverse the order of the stories, for the first assertion and provide the first vote for the first assertion, it passes
story_test.rb
def test_should_have_a_votes_association
assert_equal [votes(:two),votes(:one)], stories(:one).votes
end
def test_should_return_highest_vote_id_first
assert_equal votes(:one), stories(:one).votes.latest.first
end
I copied everything as it is in the book and have not seen an errata about this. My first conclusion was that the fixture is creating the records from bottom to top as it was declared, but that doesn't make any point
any ideas?
EDIT: I am using Rails 2.9 running in an RVM
Your fixtures aren't getting IDs 1, 2, 3, etc. like you'd expect - when you add fixtures, they get IDs based (I think) on a hash of the table name and the fixture name. To us humans, they just look like random numbers.
Rails does this so you can refer to other fixtures by name easily. For example, the fixtures
#parents.yml
vladimir:
name: Vladimir Ilyich Lenin
#children.yml
joseph:
name: Joseph Vissarionovich Stalin
parent: vladimir
actually show up in your database like
#parents.yml
vladimir:
id: <%= fixture_hash('parents', 'vladimir') %>
name: Vladimir Ilyich Lenin
#children.yml
joseph:
id: <%= fixture_hash('children', 'joseph') %>
name: Joseph Vissarionovich Stalin
parent_id: <%= fixture_hash('parents', 'vladimir') %>
Note in particular the expansion from parent: vladimir to parent_id: <%= ... %> in the child model - this is how Rails handles relations between fixtures.
Moral of the story: Don't count on your fixtures being in any particular order, and don't count on :order => :id giving you meaningful results in tests. Use results.member? objX repeatedly instead of results == [obj1, obj2, ...]. And if you need fixed IDs, hard-code them in yourself.
Hope this helps!
PS: Lenin and Stalin weren't actually related.
Xavier Holt already gave the main answer, but wanted to also mention that it is possible to force rails to read in fixtures in a certain order.
By default rails assigns its own IDs, but you can leverage the YAML omap specification to specify an ordered mapping
# countries.yml
--- !omap
- netherlands:
id: 1
title: Kingdom of Netherlands
- canada:
id: 2
title: Canada
Since you are forcing the order, you have to also specify the ID yourself manually, as shown above.
Also I'm not sure about this part, but I think once you commit to overriding the default rails generated ID and use your own, you have to do the same for all downstream references.
In the above example, suppose each country can have multiple leaders, you would have do something like
# leaders.yml
netherlands-leader:
country_id: 1 #you have to specify this now!
name: Willem-Alexander
You need to manually specify the id that refers to the previous Model (Countries)

Resources