I'm trying to create a dynamic application to create any kind of data needed through metaprogramming the MVC i tried this for models:
class DynamicRecord
attr_accessor :name, :attributes
def initialize(name, attributes = [])
raise "Error: Constant #{name} already in namespace" if name.in? Object.constants
a_new_class = Class.new(Object) do |clazz|
include Mongoid::Document
attributes.map do |attribute|
field attribute[:name], type: attribute[:type]
end
end
Object.const_set(name, a_new_class)
end
end
DynamicRecord.new('Person', [{name: :name, type: String}, {name: :email, type: String}])
person = Person.new(name: "Foo", email: "Foo#foo.com")
person.save
Then I get this error:
Mongo::Error::OperationFailure: Invalid ns [mongodb_divcad_development.] (16257)
from /home/cassiano/.rvm/gems/ruby-2.3.3/gems/mongo-2.4.1/lib/mongo/operation/result.rb:256:in `validate!'
from /home/cassiano/.rvm/gems/ruby-2.3.3/gems/mongo-2.4.1/lib/mongo/operation/write/insert.rb:60:in `block in execute_message'
from /home/cassiano/.rvm/gems/ruby-2.3.3/gems/mongo-2.4.1/lib/mongo/server/connection_pool.rb:107:in `with_connection'
from /home/cassiano/.rvm/gems/ruby-2.3.3/gems/mongo-2.4.1/lib/mongo/server.rb:242:in `with_connection'
from /home/cassiano/.rvm/gems/ruby-2.3.3/gems/mongo-2.4.1/lib/mongo/operation/write/insert.rb:59:in `execute_message'
from /home/cassiano/.rvm/gems/ruby-2.3.3/gems/mongo-2.4.1/lib/mongo/operation/write/write_command_enabled.rb:39:in `execute'
from /home/cassiano/.rvm/gems/ruby-2.3.3/gems/mongo-2.4.1/lib/mongo/collection.rb:365:in `block in insert_one'
from /home/cassiano/.rvm/gems/ruby-2.3.3/gems/mongo-2.4.1/lib/mongo/retryable.rb:112:in `write_with_retry'
from /home/cassiano/.rvm/gems/ruby-2.3.3/gems/mongo-2.4.1/lib/mongo/collection.rb:356:in `insert_one'
from /home/cassiano/.rvm/gems/ruby-2.3.3/gems/mongoid-5.2.0/lib/mongoid/query_cache.rb:182:in `insert_one_with_clear_cache'
from /home/cassiano/.rvm/gems/ruby-2.3.3/gems/mongoid-5.2.0/lib/mongoid/persistable/creatable.rb:79:in `insert_as_root'
from /home/cassiano/.rvm/gems/ruby-2.3.3/gems/mongoid-5.2.0/lib/mongoid/persistable/creatable.rb:27:in `block in insert'
from /home/cassiano/.rvm/gems/ruby-2.3.3/gems/mongoid-5.2.0/lib/mongoid/persistable/creatable.rb:118:in `block (2 levels) in prepare_insert'
from /home/cassiano/.rvm/gems/ruby-2.3.3/gems/activesupport-4.0.2/lib/active_support/callbacks.rb:373:in `_run__4510143668266298615__create__callbacks'
from /home/cassiano/.rvm/gems/ruby-2.3.3/gems/activesupport-4.0.2/lib/active_support/callbacks.rb:80:in `run_callbacks'
from /home/cassiano/.rvm/gems/ruby-2.3.3/gems/mongoid-5.2.0/lib/mongoid/interceptable.rb:138:in `run_callbacks'
from /home/cassiano/.rvm/gems/ruby-2.3.3/gems/mongoid-5.2.0/lib/mongoid/persistable/creatable.rb:117:in `block in prepare_insert'
from /home/cassiano/.rvm/gems/ruby-2.3.3/gems/activesupport-4.0.2/lib/active_support/callbacks.rb:373:in `_run__4510143668266298615__save__callbacks'
from /home/cassiano/.rvm/gems/ruby-2.3.3/gems/activesupport-4.0.2/lib/active_support/callbacks.rb:80:in `run_callbacks'
from /home/cassiano/.rvm/gems/ruby-2.3.3/gems/mongoid-5.2.0/lib/mongoid/interceptable.rb:138:in `run_callbacks'
from /home/cassiano/.rvm/gems/ruby-2.3.3/gems/mongoid-5.2.0/lib/mongoid/persistable/creatable.rb:116:in `prepare_insert'
from /home/cassiano/.rvm/gems/ruby-2.3.3/gems/mongoid-5.2.0/lib/mongoid/persistable/creatable.rb:23:in `insert'
from /home/cassiano/.rvm/gems/ruby-2.3.3/gems/mongoid-5.2.0/lib/mongoid/persistable/savable.rb:23:in `save'
from (irb):70
from /home/cassiano/.rvm/gems/ruby-2.3.3/gems/railties-4.0.2/lib/rails/commands/console.rb:90:in `start'
from /home/cassiano/.rvm/gems/ruby-2.3.3/gems/railties-4.0.2/lib/rails/commands/console.rb:9:in `start'
from /home/cassiano/.rvm/gems/ruby-2.3.3/gems/railties-4.0.2/lib/rails/commands.rb:62:in `<top (required)>'
from bin/rails:4:in `require'
from bin/rails:4:in `<main>'
This can be done? There is a better approach without falling into a Entity-attribute-value model?
Mongoid doesn't know about namespace when you try to use dynamic model. In order to fix it you should set namespace with store_in
Example:
class DynamicCollection
def self.create(collection, fields)
klass = Class.new do
include Mongoid::Document
store_in collection: collection.downcase
fields.each do |item|
field item[:name], type: item[:type]
end
end
Object.const_set(collection, klass)
end
end
fields = [
{name: 'name', type: String},
{name: 'email', type: String}
]
DynamicCollection.create('Demo', fields)
Demo.create!(name: 'SomeValue', email: 'SomeValue')
I didn't try this locally, and this could be a dumb answer...but I would change
attributes.map to attributes.each seems like map would return an array and would cause an error.
Also...
https://github.com/mongodb/mongoid/blob/master/lib/mongoid/fields.rb#L335
Looking at the source for mongoid. There is a method called add_field that you maybe able to utilize.
Related
I have a problem with the error:
ActiveRecord::RecordInvalid
caused by this:
let(:ind2){ build(:ind2) }
Rspec test:
describe '#client_free_time_validation' do
let(:ind) { build(:ind).tap {|e| p e.valid?; p e.errors}}
let(:ind2){ build(:ind2).tap {|e| p e.valid?; p e.errors} }
context 'when training is during another training' do
it 'raises an error' do
expect(ind.valid?).to be_truthy
expect(ind2.valid?).to be_falsey
# expect(ind2.errors.count).to eq 1
# expect(ind2.errors[:base]).to eq(['Masz w tym czasie inny trening.'])
end
end
Factory:
FactoryGirl.define do
factory :individual_training do
date_of_training { Date.today.next_week.advance(days: 1) }
association :client, factory: :client
association :trainer, factory: :trainer
start_on Time.parse('12:30')
end_on Time.parse('13:30')
association :training_cost, factory: :tc2
factory :ind do
start_on Time.parse('11:00')
end_on Time.parse('12:00')
end
factory :ind2 do
start_on Time.parse('10:30')
end_on Time.parse('11:30')
end
end
end
I'm confused because similar let working in another test. I tried debugging by using tap method but it doesn't show error messages(in another case nice presents).
If I should put some additional data(how my model looks like etc.), please write.
I saw that if I comment the first let or second, the test passes. It looks at situations like two let(ind and ind2) couldn't work together.
Example values of attributes generate by test:
#<ActiveModel::Errors:0x00000001f4ade8 #base=#<IndividualTraining id: nil, date_of_training: "2016-08-23", client_id: 28, trainer_id: 29, start_on: "2016-08-20 11:00:00", end_on: "2016-08-20 12:00:00", training_cost_id: 4>, #messages={}>
Do you have a suggestion how to debug what record is invalid?
Update:
Full error message:
Failure/Error: let(:ind2){ build(:ind2).tap {|e| p e.valid?; p e.errors} }
ActiveRecord::RecordInvalid:
Nieprawidłowy rekord
# /home/lukas/.rvm/gems/ruby-2.3.1/gems/activerecord-4.2.5.1/lib/active_record/validations.rb:79:in `raise_record_invalid'
# /home/lukas/.rvm/gems/ruby-2.3.1/gems/activerecord-4.2.5.1/lib/active_record/validations.rb:43:in `save!'
# /home/lukas/.rvm/gems/ruby-2.3.1/gems/activerecord-4.2.5.1/lib/active_record/attribute_methods/dirty.rb:29:in `save!'
# /home/lukas/.rvm/gems/ruby-2.3.1/gems/activerecord-4.2.5.1/lib/active_record/transactions.rb:291:in `block in save!'
# /home/lukas/.rvm/gems/ruby-2.3.1/gems/activerecord-4.2.5.1/lib/active_record/transactions.rb:351:in `block in with_transaction_returning_status'
# /home/lukas/.rvm/gems/ruby-2.3.1/gems/activerecord-4.2.5.1/lib/active_record/connection_adapters/abstract/database_statements.rb:213:in `block in transaction'
# /home/lukas/.rvm/gems/ruby-2.3.1/gems/activerecord-4.2.5.1/lib/active_record/connection_adapters/abstract/transaction.rb:184:in `within_new_transaction'
# /home/lukas/.rvm/gems/ruby-2.3.1/gems/activerecord-4.2.5.1/lib/active_record/connection_adapters/abstract/database_statements.rb:213:in `transaction'
# /home/lukas/.rvm/gems/ruby-2.3.1/gems/activerecord-4.2.5.1/lib/active_record/transactions.rb:220:in `transaction'
# /home/lukas/.rvm/gems/ruby-2.3.1/gems/activerecord-4.2.5.1/lib/active_record/transactions.rb:348:in `with_transaction_returning_status'
# /home/lukas/.rvm/gems/ruby-2.3.1/gems/activerecord-4.2.5.1/lib/active_record/transactions.rb:291:in `save!'
# /home/lukas/.rvm/gems/ruby-2.3.1/gems/factory_girl-4.7.0/lib/factory_girl/configuration.rb:18:in `block in initialize'
# /home/lukas/.rvm/gems/ruby-2.3.1/gems/factory_girl-4.7.0/lib/factory_girl/evaluation.rb:15:in `create'
# /home/lukas/.rvm/gems/ruby-2.3.1/gems/factory_girl-4.7.0/lib/factory_girl/strategy/create.rb:12:in `block in result'
# /home/lukas/.rvm/gems/ruby-2.3.1/gems/factory_girl-4.7.0/lib/factory_girl/strategy/create.rb:9:in `tap'
# /home/lukas/.rvm/gems/ruby-2.3.1/gems/factory_girl-4.7.0/lib/factory_girl/strategy/create.rb:9:in `result'
# /home/lukas/.rvm/gems/ruby-2.3.1/gems/factory_girl-4.7.0/lib/factory_girl/factory.rb:42:in `run'
# /home/lukas/.rvm/gems/ruby-2.3.1/gems/factory_girl-4.7.0/lib/factory_girl/factory_runner.rb:29:in `block in run'
# /home/lukas/.rvm/gems/ruby-2.3.1/gems/activesupport-4.2.5.1/lib/active_support/notifications.rb:166:in `instrument'
# /home/lukas/.rvm/gems/ruby-2.3.1/gems/factory_girl-4.7.0/lib/factory_girl/factory_runner.rb:28:in `run'
# /home/lukas/.rvm/gems/ruby-2.3.1/gems/factory_girl-4.7.0/lib/factory_girl/strategy/build.rb:5:in `association'
# /home/lukas/.rvm/gems/ruby-2.3.1/gems/factory_girl-4.7.0/lib/factory_girl/evaluator.rb:31:in `association'
# /home/lukas/.rvm/gems/ruby-2.3.1/gems/factory_girl-4.7.0/lib/factory_girl/attribute/association.rb:19:in `block in to_proc'
# /home/lukas/.rvm/gems/ruby-2.3.1/gems/factory_girl-4.7.0/lib/factory_girl/evaluator.rb:75:in `instance_exec'
# /home/lukas/.rvm/gems/ruby-2.3.1/gems/factory_girl-4.7.0/lib/factory_girl/evaluator.rb:75:in `block in define_attribute'
# /home/lukas/.rvm/gems/ruby-2.3.1/gems/factory_girl-4.7.0/lib/factory_girl/attribute_assigner.rb:56:in `get'
# /home/lukas/.rvm/gems/ruby-2.3.1/gems/factory_girl-4.7.0/lib/factory_girl/attribute_assigner.rb:16:in `block (2 levels) in object'
# /home/lukas/.rvm/gems/ruby-2.3.1/gems/factory_girl-4.7.0/lib/factory_girl/attribute_assigner.rb:15:in `each'
# /home/lukas/.rvm/gems/ruby-2.3.1/gems/factory_girl-4.7.0/lib/factory_girl/attribute_assigner.rb:15:in `block in object'
# /home/lukas/.rvm/gems/ruby-2.3.1/gems/factory_girl-4.7.0/lib/factory_girl/attribute_assigner.rb:14:in `tap'
# /home/lukas/.rvm/gems/ruby-2.3.1/gems/factory_girl-4.7.0/lib/factory_girl/attribute_assigner.rb:14:in `object'
# /home/lukas/.rvm/gems/ruby-2.3.1/gems/factory_girl-4.7.0/lib/factory_girl/evaluation.rb:12:in `object'
# /home/lukas/.rvm/gems/ruby-2.3.1/gems/factory_girl-4.7.0/lib/factory_girl/strategy/build.rb:9:in `result'
# /home/lukas/.rvm/gems/ruby-2.3.1/gems/factory_girl-4.7.0/lib/factory_girl/factory.rb:42:in `run'
# /home/lukas/.rvm/gems/ruby-2.3.1/gems/factory_girl-4.7.0/lib/factory_girl/factory_runner.rb:29:in `block in run'
# /home/lukas/.rvm/gems/ruby-2.3.1/gems/activesupport-4.2.5.1/lib/active_support/notifications.rb:166:in `instrument'
# /home/lukas/.rvm/gems/ruby-2.3.1/gems/factory_girl-4.7.0/lib/factory_girl/factory_runner.rb:28:in `run'
# /home/lukas/.rvm/gems/ruby-2.3.1/gems/factory_girl-4.7.0/lib/factory_girl/strategy_syntax_method_registrar.rb:20:in `block in define_singular_strategy_method'
# ./spec/models/individual_training_spec.rb:60:in `block (3 levels) in <top (required)>'
# ./spec/models/individual_training_spec.rb:65:in `block (4 levels) in <top (required)>'
Update 2:
The error disappears when I set date_of_training Date.today in a factory. I also tried to set manually date like 2016-08-23, but it's still InvalidRecord. Also Date.today + 1.day not working. Any idea what can be wrong? Maybe date_of_training isn't a direct problem.
Update 3:
IndividualTraining model validations:
private
def date_and_start_on_validation
unless start_on.blank?
if date_of_training < Date.today
errors.add(:base, 'You cannot set individual training before today.')
elsif date_of_training == Date.today
if start_on <= Time.now
errors.add(:base, 'Time of today training is before current time.')
end
end
end
end
# check if trainer work while will be individual_training
def date_of_training_validation
unless start_on.blank?
trainer.work_schedules.each_with_index do |ti, ind|
if ti.day_of_week == BackendController.helpers.translate_date(date_of_training)
if (start_on.strftime('%H:%M')..end_on.strftime('%H:%M'))
.overlaps?(ti.start_time.strftime('%H:%M')..ti.end_time.strftime('%H:%M'))
break
else
errors.add(:base, 'Training is outside of trainer work schedule.')
end
elsif ind == trainer.work_schedules.size - 1
errors.add(:base, 'In this day trainer doesn't work.')
end
end
end
end
# check if client doesn't have another training or activity
def client_free_time_validation
unless start_on.blank?
client.individual_trainings_as_client.where(date_of_training: date_of_training)
.where('id != ?', id).each do |ci|
if (start_on...end_on).overlaps?(ci.start_on...ci.end_on)
errors.add(:base, 'You have another training.')
end
end
client.activities.where(day_of_week: BackendController.helpers.translate_date(date_of_training))
.each do |ca|
if (start_on...end_on).overlaps?(ca.start_on...end_on)
errors.add(:base, 'You have another activity.')
end
end
end
end
Update 4:
I noticed that if I first execute ind.valid? - it will be true and ind2 will be RecordInvalid. But when I reload and check ind2.valid? - now it is true and ind false.
Update 5:
I used the same let but separately in a different context, and rspec passed. What could be the reason, that I cannot use two let in the same context?
IndividualTraining associations
belongs_to :trainer, class_name: 'Person', foreign_key: 'trainer_id'
belongs_to :client, class_name: 'Person', foreign_key: 'client_id'
belongs_to :training_cost
client and trainer factories
FactoryGirl.define do
factory :person do
pesel { Faker::Number.number(11) }
first_name 'Thomas'
last_name 'Owel'
date_of_birth { Faker::Time.between('1970-01-01', '2000-12-31') }
email { Faker::Internet.email }
password { Faker::Internet.password }
type 'Person'
end
factory :client, parent: :person, class: 'Client' do
first_name { Faker::Name.first_name }
last_name { Faker::Name.last_name }
type 'Client'
end
factory :trainer, parent: :person, class: 'Trainer' do
first_name { Faker::Name.first_name }
last_name { Faker::Name.last_name }
type 'Trainer'
salary { Faker::Number.decimal(4, 2) }
hiredate { Faker::Time.between('2016-01-01', '2016-04-30') }
end
end
Update 6:
In another context I have this let:
let(:individual_training) { build :individual_training, trainer_id: work_schedule[:person_id] }
let(:ind2) do
build :individual_training,
trainer_id: work_schedule[:person_id],
date_of_training: Date.today.next_week.advance(days: 0),
start_on: Time.now - 1.hour,
end_on: Time.now
end
This nice works. There is no error: RecordInvalid
These could be the reason behind "Invalid record error" -
Reason - It usually happens when you use "create" and "build" together.
create method persists the instance while the build method keeps it only in memory.
Firstly, I will suggest you to use build method and please check validations related to it. There is something wrong in your validations.
I have a model that contain a field called "status".I have change it into String type in DB.And I also use enum in AASM.
here is my code:
class Card < ActiveRecord::Base
include AASM
enum status: {
default: 0,
published: 1,
deleted: 2
}
aasm column: :status, enum: true, skip_validation_on_save: true, no_direct_assignment: true do
state :default, initial: true
state :published
state :deleted
event :publish do
transitions from: :default, to: :published
end
event :delete do
transitions from: :published, to: :deleted
end
end
end
And I apply it like this:
Card card = Card.first
card.publish
No matter I call card.publish or card.delete,I will get an error like this:
NoMethodError: undefined method `name' for nil:NilClass
from /Users/MadisonRong/.rvm/gems/ruby-2.0.0-p598/gems/aasm-4.1.1/lib/aasm/core/state.rb:15:in `=='
from /Users/MadisonRong/.rvm/gems/ruby-2.0.0-p598/gems/aasm-4.1.1/lib/aasm/instance_base.rb:61:in `block in state_object_for_name'
from /Users/MadisonRong/.rvm/gems/ruby-2.0.0-p598/gems/aasm-4.1.1/lib/aasm/instance_base.rb:61:in `each'
from /Users/MadisonRong/.rvm/gems/ruby-2.0.0-p598/gems/aasm-4.1.1/lib/aasm/instance_base.rb:61:in `find'
from /Users/MadisonRong/.rvm/gems/ruby-2.0.0-p598/gems/aasm-4.1.1/lib/aasm/instance_base.rb:61:in `state_object_for_name'
from /Users/MadisonRong/.rvm/gems/ruby-2.0.0-p598/gems/aasm-4.1.1/lib/aasm/aasm.rb:62:in `aasm_fire_event'
from /Users/MadisonRong/.rvm/gems/ruby-2.0.0-p598/gems/aasm-4.1.1/lib/aasm/persistence/active_record_persistence.rb:175:in `block in aasm_fire_event'
from /Users/MadisonRong/.rvm/gems/ruby-2.0.0-p598/gems/activerecord-4.2.0/lib/active_record/connection_adapters/abstract/database_statements.rb:213:in `block in transaction'
from /Users/MadisonRong/.rvm/gems/ruby-2.0.0-p598/gems/activerecord-4.2.0/lib/active_record/connection_adapters/abstract/transaction.rb:188:in `within_new_transaction'
from /Users/MadisonRong/.rvm/gems/ruby-2.0.0-p598/gems/activerecord-4.2.0/lib/active_record/connection_adapters/abstract/database_statements.rb:213:in `transaction'
from /Users/MadisonRong/.rvm/gems/ruby-2.0.0-p598/gems/activerecord-4.2.0/lib/active_record/transactions.rb:220:in `transaction'
from /Users/MadisonRong/.rvm/gems/ruby-2.0.0-p598/gems/aasm-4.1.1/lib/aasm/persistence/active_record_persistence.rb:175:in `aasm_fire_event'
from /Users/MadisonRong/.rvm/gems/ruby-2.0.0-p598/gems/aasm-4.1.1/lib/aasm/base.rb:81:in `block in event'
from (irb):13
from /Users/MadisonRong/.rvm/gems/ruby-2.0.0-p598/gems/railties-4.2.0/lib/rails/commands/console.rb:110:in `start'
from /Users/MadisonRong/.rvm/gems/ruby-2.0.0-p598/gems/railties-4.2.0/lib/rails/commands/console.rb:9:in `start'
from /Users/MadisonRong/.rvm/gems/ruby-2.0.0-p598/gems/railties-4.2.0/lib/rails/commands/commands_tasks.rb:68:in `console'
from /Users/MadisonRong/.rvm/gems/ruby-2.0.0-p598/gems/railties-4.2.0/lib/rails/commands/commands_tasks.rb:39:in `run_command!'
from /Users/MadisonRong/.rvm/gems/ruby-2.0.0-p598/gems/railties-4.2.0/lib/rails/commands.rb:17:in `<top (required)>'
from bin/rails:4:in `require'
from bin/rails:4:in `<main>'2.0.0-p598 :014 >
It puzzle me for a few days.Any help will be appreciate.
Shouldn't it be
enum status: [
:default,
:published,
:deleted
]
? If that doesn't help, please open open an issue on GitHub and I will take a closer look at it.
Created a simple rake task to find Bikes for Sale in the USA. It works when i want to extract heading details but when I add other parameters like location, price , etc and save it to the Posts db I get error Can't cast Hash to string
Neils-MacBook-Pro-2:bike_scraper neilpatel$ rake scraper:scrape
rake aborted!
TypeError: can't cast Hash to string
/usr/local/rvm/gems/ruby-2.0.0-p247/gems/activerecord-4.1.7/lib/active_record/connection_adapters/abstract/quoting.rb:76:in `type_cast'
/usr/local/rvm/gems/ruby-2.0.0-p247/gems/activerecord-4.1.7/lib/active_record/connection_adapters/sqlite3_adapter.rb:261:in `type_cast'
/usr/local/rvm/gems/ruby-2.0.0-p247/gems/activerecord-4.1.7/lib/active_record/connection_adapters/sqlite3_adapter.rb:295:in `block in exec_query'
/usr/local/rvm/gems/ruby-2.0.0-p247/gems/activerecord-4.1.7/lib/active_record/connection_adapters/sqlite3_adapter.rb:294:in `map'
/usr/local/rvm/gems/ruby-2.0.0-p247/gems/activerecord-4.1.7/lib/active_record/connection_adapters/sqlite3_adapter.rb:294:in `exec_query'
/usr/local/rvm/gems/ruby-2.0.0-p247/gems/activerecord-4.1.7/lib/active_record/connection_adapters/abstract/database_statements.rb:68:in `exec_insert'
/usr/local/rvm/gems/ruby-2.0.0-p247/gems/activerecord-4.1.7/lib/active_record/connection_adapters/abstract/database_statements.rb:95:in `insert'
/usr/local/rvm/gems/ruby-2.0.0-p247/gems/activerecord-4.1.7/lib/active_record/connection_adapters/abstract/query_cache.rb:14:in `insert'
/usr/local/rvm/gems/ruby-2.0.0-p247/gems/activerecord-4.1.7/lib/active_record/relation.rb:64:in `insert'
/usr/local/rvm/gems/ruby-2.0.0-p247/gems/activerecord-4.1.7/lib/active_record/persistence.rb:503:in `_create_record'
/usr/local/rvm/gems/ruby-2.0.0-p247/gems/activerecord-4.1.7/lib/active_record/attribute_methods/dirty.rb:87:in `_create_record'
/usr/local/rvm/gems/ruby-2.0.0-p247/gems/activerecord-4.1.7/lib/active_record/callbacks.rb:306:in `block in _create_record'
/usr/local/rvm/gems/ruby-2.0.0-p247/gems/activesupport-4.1.7/lib/active_support/callbacks.rb:82:in `run_callbacks'
/usr/local/rvm/gems/ruby-2.0.0-p247/gems/activerecord-4.1.7/lib/active_record/callbacks.rb:306:in `_create_record'
/usr/local/rvm/gems/ruby-2.0.0-p247/gems/activerecord-4.1.7/lib/active_record/timestamp.rb:57:in `_create_record'
/usr/local/rvm/gems/ruby-2.0.0-p247/gems/activerecord-4.1.7/lib/active_record/persistence.rb:483:in `create_or_update'
/usr/local/rvm/gems/ruby-2.0.0-p247/gems/activerecord-4.1.7/lib/active_record/callbacks.rb:302:in `block in create_or_update'
/usr/local/rvm/gems/ruby-2.0.0-p247/gems/activesupport-4.1.7/lib/active_support/callbacks.rb:82:in `run_callbacks'
/usr/local/rvm/gems/ruby-2.0.0-p247/gems/activerecord-4.1.7/lib/active_record/callbacks.rb:302:in `create_or_update'
/usr/local/rvm/gems/ruby-2.0.0-p247/gems/activerecord-4.1.7/lib/active_record/persistence.rb:103:in `save'
/usr/local/rvm/gems/ruby-2.0.0-p247/gems/activerecord-4.1.7/lib/active_record/validations.rb:51:in `save'
/usr/local/rvm/gems/ruby-2.0.0-p247/gems/activerecord-4.1.7/lib/active_record/attribute_methods/dirty.rb:21:in `save'
/usr/local/rvm/gems/ruby-2.0.0-p247/gems/activerecord-4.1.7/lib/active_record/transactions.rb:268:in `block (2 levels) in save'
/usr/local/rvm/gems/ruby-2.0.0-p247/gems/activerecord-4.1.7/lib/active_record/transactions.rb:329:in `block in with_transaction_returning_status'
/usr/local/rvm/gems/ruby-2.0.0-p247/gems/activerecord-4.1.7/lib/active_record/connection_adapters/abstract/database_statements.rb:201:in `block in transaction'
/usr/local/rvm/gems/ruby-2.0.0-p247/gems/activerecord-4.1.7/lib/active_record/connection_adapters/abstract/database_statements.rb:209:in `within_new_transaction'
/usr/local/rvm/gems/ruby-2.0.0-p247/gems/activerecord-4.1.7/lib/active_record/connection_adapters/abstract/database_statements.rb:201:in `transaction'
/usr/local/rvm/gems/ruby-2.0.0-p247/gems/activerecord-4.1.7/lib/active_record/transactions.rb:208:in `transaction'
/usr/local/rvm/gems/ruby-2.0.0-p247/gems/activerecord-4.1.7/lib/active_record/transactions.rb:326:in `with_transaction_returning_status'
/usr/local/rvm/gems/ruby-2.0.0-p247/gems/activerecord-4.1.7/lib/active_record/transactions.rb:268:in `block in save'
/usr/local/rvm/gems/ruby-2.0.0-p247/gems/activerecord-4.1.7/lib/active_record/transactions.rb:283:in `rollback_active_record_state!'
/usr/local/rvm/gems/ruby-2.0.0-p247/gems/activerecord-4.1.7/lib/active_record/transactions.rb:267:in `save'
/Users/neilpatel/Desktop/Rails/bike_scraper/lib/tasks/scraper.rake:53:in `block (3 levels) in <top (required)>'
/Users/neilpatel/Desktop/Rails/bike_scraper/lib/tasks/scraper.rake:38:in `each'
/Users/neilpatel/Desktop/Rails/bike_scraper/lib/tasks/scraper.rake:38:in `block (2 levels) in <top (required)>'
Tasks: TOP => scraper:scrape
(See full trace by running task with --trace)
scraper.rake
namespace :scraper do
desc "Fetch Craigslist posts from 3Taps"
task scrape: :environment do
require 'open-uri' #ruby gem
require 'JSON'
# Set API token and URL
auth_token = "fadddddddd4a23a1cc86e0d"
polling_url = "http://polling.3taps.com/poll"
# Specify request parameters
params = {
auth_token: auth_token,
anchor: 2109915749,
source: "CRAIG",
category_group: "SSSS",
category: "SBIK",
'location.country' => "USA",
retvals: "location,external_url,heading,body,timestamp,price,images,annotations"
}
# Prepare API request
uri = URI.parse(polling_url)
uri.query = URI.encode_www_form(params)
# Submit request -hitting enter
result = JSON.parse(open(uri).read)
# Display results to screen (put string - display information)
#puts result["postings"].second["location"]
#store results in database
# Create new Post
result["postings"].each do |posting|
# Create new Post
#post = Post.new
#post.heading = posting["heading"]
#post.body = posting["body"]
#post.price = posting["price"]
#post.state = posting["location"]
#post.external_url = posting["external_url"]
#post.timestamp = posting["timestamp"]
# Save Post
#post.save
end
end
desc "TODO"
task destroy_all_posts: :environment do
end
end
Posts.db
class CreatePosts < ActiveRecord::Migration
def change
create_table :posts do |t|
t.string :heading
t.text :body
t.decimal :price
t.string :state
t.string :external_url
t.string :timestamp
t.timestamps
end
end
end
The error is coming from your #post.save line, so one of those fields that came back in posting is a Hash, not a String as you expect. It won't be price, so just check all the others by putsing them.
Update
I just ran your code, it's posting["location"] that's a Hash
Further Update
Looks like you just want the state out of that hash, ie.
#post.state = posting["location"]["state"]
I am new to rails and am following the Depot application in the Pragmatic Agile Web development with rails and I am having an odd problem.
In my product model I created a validator for confirming that the image asked for in the image url field actually exist as an asset. Here is my product model code.
class Product < ActiveRecord::Base
attr_accessible :description, :image_url, :price, :title
validates :description, :price, :title, :presence => true
validate :image_url_exists, on: :create
def image_url_exists
if Rails.application.assets.find_asset(image_url) == nil
errors.add(:image_url, 'is not valid. The image does not exist.')
end
end
end
Now the problem is when I run my unit test. Here is what it is:
require 'test_helper'
class ProductTest < ActiveSupport::TestCase
test "the products attributes should not be empty" do
p = Product.new
assert p.invalid?
end
end
But doing so triggers a bunch of errors in my code. Without the custom validtor, everything seems to work just fine. Here are the errors I am currently getting.
test_the_products_attributes_should_not_be_empty(ProductTest):
TypeError: can't convert nil into String
/var/lib/gems/1.9.1/gems/sprockets-2.2.2/lib/sprockets/base.rb:156:in `initialize'
/var/lib/gems/1.9.1/gems/sprockets-2.2.2/lib/sprockets/base.rb:156:in `new'
/var/lib/gems/1.9.1/gems/sprockets-2.2.2/lib/sprockets/base.rb:156:in `find_asset'
/var/lib/gems/1.9.1/gems/sprockets-2.2.2/lib/sprockets/index.rb:60:in `find_asset'
/var/lib/gems/1.9.1/gems/sprockets-2.2.2/lib/sprockets/environment.rb:78:in `find_asset'
/home/saurabh/Desktop/SCRIPTS/Rails/depot/app/models/product.rb:6:in `image_url_exists'
/var/lib/gems/1.9.1/gems/activesupport-3.2.9/lib/active_support/callbacks.rb:418:in `_run__4343689776242734370__validate__107120755283260520__callbacks'
/var/lib/gems/1.9.1/gems/activesupport-3.2.9/lib/active_support/callbacks.rb:405:in `__run_callback'
/var/lib/gems/1.9.1/gems/activesupport-3.2.9/lib/active_support/callbacks.rb:385:in `_run_validate_callbacks'
/var/lib/gems/1.9.1/gems/activesupport-3.2.9/lib/active_support/callbacks.rb:81:in `run_callbacks'
/var/lib/gems/1.9.1/gems/activemodel-3.2.9/lib/active_model/validations.rb:228:in `run_validations!'
/var/lib/gems/1.9.1/gems/activemodel-3.2.9/lib/active_model/validations/callbacks.rb:53:in `block in run_validations!'
/var/lib/gems/1.9.1/gems/activesupport-3.2.9/lib/active_support/callbacks.rb:403:in `_run__4343689776242734370__validation__107120755283260520__callbacks'
/var/lib/gems/1.9.1/gems/activesupport-3.2.9/lib/active_support/callbacks.rb:405:in `__run_callback'
/var/lib/gems/1.9.1/gems/activesupport-3.2.9/lib/active_support/callbacks.rb:385:in `_run_validation_callbacks'
/var/lib/gems/1.9.1/gems/activesupport-3.2.9/lib/active_support/callbacks.rb:81:in `run_callbacks'
/var/lib/gems/1.9.1/gems/activemodel-3.2.9/lib/active_model/validations/callbacks.rb:53:in `run_validations!'
/var/lib/gems/1.9.1/gems/activemodel-3.2.9/lib/active_model/validations.rb:195:in `valid?'
/var/lib/gems/1.9.1/gems/activerecord-3.2.9/lib/active_record/validations.rb:69:in `valid?'
/var/lib/gems/1.9.1/gems/activemodel-3.2.9/lib/active_model/validations.rb:203:in `invalid?'
The problem is Rails.application.assets.find_asset(image_url), image_url is nil when you create a refresh object at test:
p = Product.new # Here p.image_url => nil
You can find the reason of the error looking at log
/var/lib/gems/1.9.1/gems/sprockets-2.2.2/lib/sprockets/base.rb:156:in `initialize'
Here (link) the line 156 where error happens, path was nil here.
So to solve this problem you need to add a condition at your if to check if image_url isn't nil, here is my sugestion
if self.image_url.nil? || Rails.application.assets.find_asset(self.image_url).nil?
errors.add(:image_url, 'is not valid. The image does not exist.')
end
Let's say I had the email address like putin-crab#президент.рф
How to validate that address in rails 3.1?
My Model(i use Mongoid):
#encoding: utf-8
class User
include Mongoid::Document
field :email, :type => String
validates :email, :presence => true, :format => { :with => RFC822::EMAIL }
end
For validations reqexp i use gem https://github.com/dim/rfc-822
in rails console (normal email):
ruby-1.9.2-p290 :001 > usr = User.new( :email => "pretty#gmail.com" )
=> #<User _id: 4ec627cf4934db7e4d000001, _type: nil, email: "pretty#gmail.com">
ruby-1.9.2-p290 :002 > usr.valid?
=> true
in rails console (fu##ing email):
ruby-1.9.2-p290 :003 > usr = User.new( :email => "putin-crab#президент.рф" )
=> #<User _id: 4ec627f44934db7e4d000002, _type: nil, email: "putin-crab#президент.рф">
ruby-1.9.2-p290 :004 > usr.valid?
Encoding::CompatibilityError: incompatible encoding regexp match (ASCII-8BIT regexp with UTF-8 string)
from /home/username/.rvm/gems/ruby-1.9.2-p290#rail31/gems/activemodel-3.1.1/lib/active_model/validations/format.rb:9:in `=~'
from /home/username/.rvm/gems/ruby-1.9.2-p290#rail31/gems/activemodel-3.1.1/lib/active_model/validations/format.rb:9:in `!~'
from /home/username/.rvm/gems/ruby-1.9.2-p290#rail31/gems/activemodel-3.1.1/lib/active_model/validations/format.rb:9:in `validate_each'
from /home/username/.rvm/gems/ruby-1.9.2-p290#rail31/gems/activemodel-3.1.1/lib/active_model/validator.rb:153:in `block in validate'
from /home/username/.rvm/gems/ruby-1.9.2-p290#rail31/gems/activemodel-3.1.1/lib/active_model/validator.rb:150:in `each'
from /home/username/.rvm/gems/ruby-1.9.2-p290#rail31/gems/activemodel-3.1.1/lib/active_model/validator.rb:150:in `validate'
from /home/username/.rvm/gems/ruby-1.9.2-p290#rail31/gems/activesupport-3.1.1/lib/active_support/callbacks.rb:302:in `_callback_before_13'
from /home/username/.rvm/gems/ruby-1.9.2-p290#rail31/gems/activesupport-3.1.1/lib/active_support/callbacks.rb:404:in `_run_validate_callbacks'
from /home/username/.rvm/gems/ruby-1.9.2-p290#rail31/gems/activesupport-3.1.1/lib/active_support/callbacks.rb:81:in `run_callbacks'
from /home/username/.rvm/gems/ruby-1.9.2-p290#rail31/gems/mongoid-2.3.3/lib/mongoid/callbacks.rb:42:in `block in run_callbacks'
from /home/username/.rvm/gems/ruby-1.9.2-p290#rail31/gems/mongoid-2.3.3/lib/mongoid/callbacks.rb:67:in `call'
from /home/username/.rvm/gems/ruby-1.9.2-p290#rail31/gems/mongoid-2.3.3/lib/mongoid/callbacks.rb:67:in `run_cascading_callbacks'
from /home/username/.rvm/gems/ruby-1.9.2-p290#rail31/gems/mongoid-2.3.3/lib/mongoid/callbacks.rb:41:in `run_callbacks'
from /home/username/.rvm/gems/ruby-1.9.2-p290#rail31/gems/activemodel-3.1.1/lib/active_model/validations.rb:212:in `run_validations!'
from /home/username/.rvm/gems/ruby-1.9.2-p290#rail31/gems/activemodel-3.1.1/lib/active_model/validations/callbacks.rb:53:in `block in run_validations!'
from /home/username/.rvm/gems/ruby-1.9.2-p290#rail31/gems/activesupport-3.1.1/lib/active_support/callbacks.rb:390:in `_run_validation_callbacks'
from /home/username/.rvm/gems/ruby-1.9.2-p290#rail31/gems/activesupport-3.1.1/lib/active_support/callbacks.rb:81:in `run_callbacks'
from /home/username/.rvm/gems/ruby-1.9.2-p290#rail31/gems/mongoid-2.3.3/lib/mongoid/callbacks.rb:42:in `block in run_callbacks'
from /home/username/.rvm/gems/ruby-1.9.2-p290#rail31/gems/mongoid-2.3.3/lib/mongoid/callbacks.rb:67:in `call'
from /home/username/.rvm/gems/ruby-1.9.2-p290#rail31/gems/mongoid-2.3.3/lib/mongoid/callbacks.rb:67:in `run_cascading_callbacks'
from /home/username/.rvm/gems/ruby-1.9.2-p290#rail31/gems/mongoid-2.3.3/lib/mongoid/callbacks.rb:41:in `run_callbacks'
from /home/username/.rvm/gems/ruby-1.9.2-p290#rail31/gems/activemodel-3.1.1/lib/active_model/validations/callbacks.rb:53:in `run_validations!'
from /home/username/.rvm/gems/ruby-1.9.2-p290#rail31/gems/activemodel-3.1.1/lib/active_model/validations.rb:179:in `valid?'
from /home/username/.rvm/gems/ruby-1.9.2-p290#rail31/gems/mongoid-2.3.3/lib/mongoid/validations.rb:70:in `valid?'
from (irb):4
from /home/username/.rvm/gems/ruby-1.9.2-p290#rail31/gems/railties-3.1.1/lib/rails/commands/console.rb:45:in `start'
from /home/username/.rvm/gems/ruby-1.9.2-p290#rail31/gems/railties-3.1.1/lib/rails/commands/console.rb:8:in `start'
from /home/username/.rvm/gems/ruby-1.9.2-p290#rail31/gems/railties-3.1.1/lib/rails/commands.rb:40:in `<top (required)>'
from script/rails:6:in `require'
Emails cannot be recognized by Regexps because they are not a Regular language.
There are several good ways to validate an email address in Ruby (and Rails), each with various trade-offs:
If you only want to validate that it's the correct format, use a dedicated specific parser like the one from TMail, and see if the input is accepted (parsed successfully) (NOT A REGEXP). For example https://github.com/codyrobbins/active-model-email-validator
Once the email is known to have a correct format you can go a step further, and "talk to the internet" by doing DNS queries to see that the email's domain resolves and has mails servers (MX records) specified like https://github.com/Empact/validates_email_veracity_of although this might be too much.