I am trying to build a FactoryGirl factory for the Client.rb model:
Client.rb
enum status: [ :unregistered, :registered ]
has_many :quotation_requests
#Validations
validates :first_name,
presence: true,
length: {minimum: 2}
validates :last_name,
presence: true,
length: {minimum: 2}
validates :email, email: true
validates :status, presence: true
Factory:
FactoryGirl.define do
factory :client do
first_name "Peter"
last_name "Johnson"
sequence(:email) { |n| "peterjohnson#{n}#example.com" }
password "somepassword"
status "unregistered"
end
end
client_spec.rb
require 'rails_helper'
RSpec.describe Client, type: :model do
describe 'factory' do
it "has a valid factory" do
expect(FactoryGirl.build(:client).to be_valid
end
end
end
I get the following errorL
1) Client factory has a valid factory
Failure/Error: expect(FactoryGirl.build(:client, status: 'unregistered')).to be_valid
expected #<Client id: nil, email: "peterjohnson1#example.com", encrypted_password: "$2a$04$urndfdXNfKVqYB5t3kERZ.c.DUitIVXEZ6f19FNYZ2C...", first_name: "Peter", last_name: "Johnson", status: "0", reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: nil, sign_in_count: 0, current_sign_in_at: nil, last_sign_in_at: nil, current_sign_in_ip: nil, last_sign_in_ip: nil, created_at: nil, updated_at: nil> to be valid, but got errors: Status can't be blank
The error is that Status can't be blank.
I don't understand how this is possible as the factory is clearly assigning a value to the status attribute.
How can I get this factory to build a valid client object?
Rails 4.2
Using factory_girl 4.7.0
Using factory_girl_rails 4.7.0
This error was caused by the data type I used for the status attribute. I chose string instead of integer.
I solved the problem by running a new migration to change the data type of the status to integer.
class ChangeColumnTypeClientStatus < ActiveRecord::Migration
def change
change_column :clients, :status, :integer, default: 0
end
end
Now it works perfectly.
I think that you forgot the
let(:client) { FactoryGirl.create(:client) }
on your client_spec.rb
Where're you creating the client object?
Other issue may be that you assign on Factory:
status "unregistered"
instead of:
status :unregistered
as a symbol or due to is an enum maybe you should make
status 0 # :unregistered
Related
In scala play application, I am trying to parse uuid as a json response but getting error:
play.api.libs.json.Json.parse(s"""
{
"id" : "ac435876-fe73-4385-a9dd-af54ce2d7a7d"
}
""")
Error- play.api.http.HttpErrorHandlerExceptions$$anon$1: Execution exception[[JsonParseException: Unrecognized token 'C': was expecting (JSON String, Number, Array, Object or token 'null', 'true' or 'false') at [Source: (String)"
I am facing an issue while learning Elixir & Ecto. The idea is to build a standard posts/comments page to understand how the basics work. I am at a point where I have schemas defined, a migration written and encounter an error when trying to insert data into the database (PostgreSQL) via the Repo. I have done a fair deal of web searching and documentation reading, which leads me to believe it's a scenario that should just work and I am making a stupid mistake somewhere, which I just can't see.
They are defined as follows:
lib/hello/schemas.ex
defmodule Hello.PostAuthor do
use Ecto.Schema
schema "post_authors" do
field :name, :string
end
end
defmodule Hello.CommentAuthor do
use Ecto.Schema
schema "comment_authors" do
field :name, :string
end
end
defmodule Hello.Comment do
use Ecto.Schema
schema "comments" do
has_one :author, Hello.CommentAuthor
field :date, :date
field :body, :string
end
end
defmodule Hello.Post do
use Ecto.Schema
schema "posts" do
has_one :author, Hello.PostAuthor
field :date, :date
field :body, :string
has_many :comments, Hello.Comment
end
end
as you can see, I have two fields with :date type - on post and comment schemas. The corresponding migration is as follows:
defmodule Hello.Repo.Migrations.CreatePosts do
use Ecto.Migration
def change do
create table(:post_authors) do
add :name, :string
end
create table(:comment_authors) do
add :name, :string
end
create table(:comments) do
add :author, references(:comment_authors)
add :date, :date
add :body, :string
end
create table(:posts) do
add :author, references(:post_authors), null: false
add :date, :date
add :body, :string
add :comments, references(:comments)
timestamps()
end
end
end
Now, when I start iex -S mix I can successfully create all structs:
iex(1)> post_author = %Hello.PostAuthor{name: "John"}
%Hello.PostAuthor{
__meta__: #Ecto.Schema.Metadata<:built, "post_authors">,
id: nil,
name: "John"
}
iex(2)> comment_author = %Hello.PostAuthor{name: "Adam"}
%Hello.PostAuthor{
__meta__: #Ecto.Schema.Metadata<:built, "post_authors">,
id: nil,
name: "Adam"
}
iex(3)> comment = %Hello.Comment{author: comment_author, date: ~D[2019-01-01], body: "this is a comment"}
%Hello.Comment{
__meta__: #Ecto.Schema.Metadata<:built, "comments">,
author: %Hello.PostAuthor{
__meta__: #Ecto.Schema.Metadata<:built, "post_authors">,
id: nil,
name: "Adam"
},
body: "this is a comment",
date: ~D[2019-01-01],
id: nil
}
iex(4)> post = %Hello.Post{author: post_author, date: ~D[2019-01-01], body: "this is a post", comments: [comment]}
%Hello.Post{
__meta__: #Ecto.Schema.Metadata<:built, "posts">,
author: %Hello.PostAuthor{
__meta__: #Ecto.Schema.Metadata<:built, "post_authors">,
id: nil,
name: "John"
},
body: "this is a post",
comments: [%Hello.Comment{
__meta__: #Ecto.Schema.Metadata<:built, "comments">,
author: %Hello.PostAuthor{
__meta__: #Ecto.Schema.Metadata<:built, "post_authors">,
id: nil,
name: "Adam"
},
body: "this is a comment",
date: ~D[2019-01-01],
id: nil
}],
date: ~D[2019-01-01],
id: nil
}
The problem arises when I call Hello.Repo.insert(post) (where post is the struct representing the Hello.Post schema). I receive what looks like serialization error:
iex(8)> Hello.Repo.insert(post) [debug] QUERY OK db=0.1ms
begin []
[debug] QUERY ERROR db=1.6ms
INSERT INTO "posts" ("body","date") VALUES ($1,$2) RETURNING "id" ["this is a post", ~D[2019-01-01]]
[debug] QUERY OK db=0.1ms
rollback []
** (DBConnection.EncodeError) Postgrex expected a binary, got ~D[2019-01-01]. Please make sure the value you are passing matches the definition in your table or in your query or convert the value accordingly.
(postgrex) lib/postgrex/type_module.ex:897: Postgrex.DefaultTypes.encode_params/3
(postgrex) lib/postgrex/query.ex:75: DBConnection.Query.Postgrex.Query.encode/3
(db_connection) lib/db_connection.ex:1148: DBConnection.encode/5
(db_connection) lib/db_connection.ex:1246: DBConnection.run_prepare_execute/5
(db_connection) lib/db_connection.ex:540: DBConnection.parsed_prepare_execute/5
(db_connection) lib/db_connection.ex:533: DBConnection.prepare_execute/4
(postgrex) lib/postgrex.ex:198: Postgrex.query/4
(ecto_sql) lib/ecto/adapters/sql.ex:666: Ecto.Adapters.SQL.struct/10
(ecto) lib/ecto/repo/schema.ex:651: Ecto.Repo.Schema.apply/4
(ecto) lib/ecto/repo/schema.ex:262: anonymous fn/15 in Ecto.Repo.Schema.do_insert/4
(ecto) lib/ecto/repo/schema.ex:916: anonymous fn/3 in Ecto.Repo.Schema.wrap_in_transaction/6
(ecto_sql) lib/ecto/adapters/sql.ex:898: anonymous fn/3 in Ecto.Adapters.SQL.checkout_or_transaction/4
(db_connection) lib/db_connection.ex:1415: DBConnection.run_transaction/4
This is where I am lost. Both the schema and the migration are expecting a :date . I believe that ~D[2019-01-01] is a date. PostgreSQL defines date as a 4 byte binary value. I am expecting Ecto.Adapters.Postgres to translate elixir date struct into the Postgres binary value. This is not happening. Why?
Struct itself is just raw data. You should go through Ecto.Changeset as shown in the documentation, specifically to all types to be cast to the respective DB types with Ecto.Changeset.cast/4.
The conversion will be done automagically, but you need to explicitly call cast/4 (hence the Changeset,) otherwise the adapter has no idea of how to convert your ecto types.
tl,dr: How can I ensure that the order of my has_many, through nested attributes, with an attribute value set in the build, are always assigned the same nested parameters hash key number (0, 1, etc.) and always appear in the form in the same order?
Hopefully I can describe this so it makes sense. I have a small prototype app that simulates a simple bank transfer between two accounts, a source account and a destination account. I have a Transfer class, an Account class and a TransferAccounts class that is the through join for the many_to_many association between Transfer and Account.
Here is the new action in the TransfersController:
def new
#transfer = Transfer.new
#transfer.transfer_accounts.build(account_transfer_role: 'source').build_account
#transfer.transfer_accounts.build(account_transfer_role: 'destination').build_account
bank_selections
account_selections
end
And the strong parameters:
def transfer_params
params.require(:transfer).
permit(:name, :description,
transfer_accounts_attributes:
[:id, :account_id, :account_transfer_role,
account_attributes:
[:id, :bank_id, :name, :description, :user_name,
:password, :routing_number, :account_number
]
])
end
So, the two transfer_accounts associated with a transfer each have an account_transfer_role attribute, with one of them set to source and the other set to destination.
Now, when filling in the form and submitting, the parameters look like the following in console:
Parameters: {"utf8"=>"✓", "authenticity_token"=>"xxxxxxxxxxxxxxxxxx==",
"transfer"=>{"name"=>"Test Transfer 2", "description"=>"Second test transfer",
"transfer_accounts_attributes"=>{"0"=>{"account_transfer_role"=>"source", "account_id"=>"1",
"account_attributes"=>{"bank_id"=>"1", "name"=>"George's Checking",
"description"=>"George's personal checking account", "user_name"=>"georgeckg",
"password"=>"[FILTERED]", "account_number"=>"111111111", "routing_number"=>"101010101",
"id"=>"3"}, "id"=>"3"}, "1"=>{"account_transfer_role"=>"destination", "account_id"=>"2",
"account_attributes"=>{"bank_id"=>"2", "name"=>"George's Savings",
"description"=>"George's personal savings account", "user_name"=>"georgesav",
"password"=>"[FILTERED]", "account_number"=>"111101111", "routing_number"=>"100100100",
"id"=>"4"}, "id"=>"4"}}}, "commit"=>"Update Transfer", "id"=>"2"}
As you can see, each transfer_account in the the transfer_account_attributes hash has an id key, either a 0 or a 1 (e.g. ..."0"=>{"account_transfer_role"=>"source"...). Now, I have been working under the assumption (which I thought might come back to bite me, and it has) that because of the order they are built in the new action, that the source transfer_account would always have an id key of 0 and the destination transfer_account would always have an id key of 1, which led me to use these id keys elsewhere in the controller as though 0 represented source and 1 represented destination.
And all seemed to be working fine until I was trying different permutations of creating new or using existing accounts, creating new or editing existing transfers when suddenly the form appears with destination listed first and source second, which hadn't occurred before, causing the entries to now have destination associated with 0 and source associated with 1, breaking the code in the controller referred to above.
To make it clearer, here is the form:
#transfer_form
= simple_form_for #transfer do |t|
.form-inputs
= t.input :name, label: 'Transfer Name'
= t.input :description, required: false, label: 'Transfer Description'
= t.simple_fields_for :transfer_accounts do |ta|
- role = ta.object.account_transfer_role.titleize
= ta.input :account_transfer_role, as: :hidden
= ta.input :account_id, collection: #valid_accounts,
include_blank: 'Select account...',
label: "#{ role } Account",
error: 'Account selection is required.'
.account_fields{id: "#{ role.downcase }_account_fields"}
= ta.simple_fields_for :account do |a|
= a.input :bank_id, collection: #valid_banks,
include_blank: 'Select bank...',
label: "#{ role } Bank",
error: 'Bank selection is required.',
class: "#{ role.downcase }_account_input_field"
= a.input :name, label: "#{ role } Account Name",
class: "#{ role.downcase }_account_input_field"
= a.input :description, required: false,
label: "#{ role } Account Description",
class: "#{ role.downcase }_account_input_field"
= a.input :user_name, label: "#{ role } Account User Name",
class: "#{ role.downcase }_account_input_field"
= a.input :password, label: "#{ role } Account Password",
class: "#{ role.downcase }_account_input_field"
= a.input :account_number, label: "#{ role } Account Number",
class: "#{ role.downcase }_account_input_field"
= a.input :routing_number, label: "#{ role } Account Routing Number",
class: "#{ role.downcase }_account_input_field"
= t.submit
How do I ensure that source is always first and, thus, always associated with the id key 0 and destination is always second, always associated with the id key 1?
The answer appears to be as simple as changing the :transfer_accounts association line in my Transfer model from this:
has_many :transfer_accounts, inverse_of: :transfer
to this:
has_many :transfer_accounts, -> { order('account_transfer_role DESC') }, inverse_of: :transfer
If anyone believes it is not doing what I think it is doing, please let me know, because, at the moment it appears to be resolving my issue.
Have no idea why I am getting this error but my code:
angular.module('authAppApp')
.factory 'AuthService', (Session) ->
# Service logic
# ...
# Public API here
{
login: (creds)->
res =
id: 1,
user:
id: 1,
role: "admin"
Session.create(res.id, res.user.id, res.user.role)
return
}
Error:
[stdin]:30:14: error: unexpected .
Session.create(res.id, res.user.id, res.user.role)
^
This also happens with console.log
Why?
It looks like your indentation is off:
res =
id: 1,
user:
id: 1,
role: "admin"
Session.create(res.id, res.user.id, res.user.role)
return
The indentation of Session should match the indentation of res =. Otherwise, the coffeescript compiler will parse it as a property of the object you are setting res to. In particular, it's probably expecting a : and a value after Session.
this is for my login form which uses propel as user provider, I get this error which I can understand from, that identifiers are not quoted:
and error:
Unable to execute SELECT statement [SELECT user.id, user.username, user.password, user.email, user.type, user.first_name, user.last_name, user.national_code, user.personal_code, user.role, user.card, user.university_id, user.salt, user.active, user.created_at, user.updated_at FROM user WHERE user.username=:p1 LIMIT 1] [wrapped: SQLSTATE[42601]: Syntax error: 7 ERROR: syntax error at or near "." LINE 1: SELECT user.id, user.username, user.password, user.email, us... ^]
my propel configuration:
propel:
path: "%kernel.root_dir%/../vendor/propel"
phing_path: "%kernel.root_dir%/../vendor/phing"
logging: %kernel.debug%
dbal:
default_connection: default
connections:
default:
driver: %database_driver%
user: %database_user%
password: %database_password%
dsn: %database_driver%:host=%database_host%;dbname=%database_name%
options:
ATTR_PERSISTENT: false
attributes:
ATTR_EMULATE_PREPARES: true
settings:
charset: { value: UTF8 }
build_properties:
propel.database: %database_driver%
propel.database.url: ${propel.dsn}
propel.database.buildUrl: ${propel.database.url}
propel.database.createUrl: ${propel.database.buildUrl}
propel.database.user: %database_user%
propel.database.password: %database_password%
propel.platform.class: platform.${propel.database}Platform
propel.disableIdentifierQuoting: false
and also my provider config:
providers:
main:
propel:
class: National\PublicationBundle\Model\User
property: username
is something wrong with my config? I also found this on github and changed my code accordingly but it did change nothing, what I did:
\$sql = sprintf(
'$query',
implode(', ', array_map(function(\$e) { return '\"'.\$e.'\"' ; }, \$modifiedColumns)),
implode(', ', array_keys(\$modifiedColumns))
);
one more thing: when I generate sql wih php app/console propel:build:sql, sql codes are quoted correctly.
answer: user is a reserved word! so just changed it to users and solved! :\