Ruby Data_Mapper resource not able to be saved - expecting different data type - mysql

I'm attempting to save some information relating to real estate in my local area.
I'm using Ruby with the Data_Mapper gem to persist the data to a local MySQL database.
The models currently look like thus:
class Property
include DataMapper::Resource
property :id, Serial
property :num, String
property :street, String
property :street_type, String
property :price, String
property :block_size, String
property :unimproved_value, String
property :found, DateTime
property :last_seen, DateTime
belongs_to :suburb
end
class Suburb
include DataMapper::Resource
property :id, Serial
property :name, String
property :post_code, Integer
has n, :properties
belongs_to :state
end
class State
include DataMapper::Resource
property :id, Serial
property :name, String
property :abbreviation, String
has n, :suburbs
end
I'm able to create and save Properties and States, however when I attempt to create a Suburb I get the following error:
irb(main):006:0> Suburb.create(:name => "Test", :post_code => 4321)
ArgumentError: arguments may be 1 or 2 Integers, or 1 Range object, was: [:name]
from /var/lib/gems/1.9.1/gems/dm-core-1.2.1/lib/dm-core/collection.rb:390:in `[]'
from /var/lib/gems/1.9.1/gems/dm-core-1.2.1/lib/dm-core/model/property.rb:236:in `name='
from /var/lib/gems/1.9.1/gems/dm-core-1.2.1/lib/dm-core/resource.rb:336:in `block in attributes='
from /var/lib/gems/1.9.1/gems/dm-core-1.2.1/lib/dm-core/resource.rb:332:in `each'
from /var/lib/gems/1.9.1/gems/dm-core-1.2.1/lib/dm-core/resource.rb:332:in `attributes='
from /var/lib/gems/1.9.1/gems/dm-core-1.2.1/lib/dm-core/resource.rb:755:in `initialize'
from /var/lib/gems/1.9.1/gems/dm-validations-1.2.0/lib/dm-validations.rb:129:in `new'
from /var/lib/gems/1.9.1/gems/dm-validations-1.2.0/lib/dm-validations.rb:129:in `create'
from (irb):6
from /usr/bin/irb:12:in `<main>'
Is this error because I am also not defining a State when creating the object? I've tried different data types for the properties but I still receive the same error. The only thing I take away from this is possibly because I have a belongs_to and has_many relationship?
Any help is greatly appreciated!

The issue was with the spelling of Properties when referencing it in the model for Suburbs. The correct spelling (according to Ruby) is Propertys.

Have you tried creating a Suburb by adding it to State's suburbs collection?
Assuming state has been created:
suburb = Suburb.new(:name => "Test", :post_code => 4321)
state.suburbs << suburb
state.save

Related

Active Record 4.x and MySQL table column type without using migrations

I'm doing some test with Sinatra v1.4.4 and Active Record v4.0.2. I've created a DBase and a table named Company with Mysql Workbench. In table Company there are two fields lat & long of DECIMAL(10,8) and DECIMAL(11,8) type respectively. Without using migrations I defined the Company model as follow:
class Company < ActiveRecord::Base
end
Everything works except the fact that lat and lng are served as string and not as float/decimal. Is there any way to define the type in the above Class Company definition. Here you can find the Sinatra route serving the JSON response:
get '/companies/:companyId' do |companyId|
begin
gotCompany = Company.find(companyId)
[200, {'Content-Type' => 'application/json'}, [{code:200, company: gotCompany.attributes, message: t.company.found}.to_json]]
rescue
[404, {'Content-Type' => 'application/json'}, [{code:404, message:t.company.not_found}.to_json]]
end
end
Active Record correctly recognize them as decimal. For example, executing this code:
Company.columns.each {|c| puts c.type}
Maybe its the Active Record object attributes method typecast?
Thanks,
Luca
You can wrap the getter methods for those attributes and cast them:
class Company < ActiveRecord::Base
def lat
read_attribute(:lat).to_f
end
def lng
read_attribute(:lng).to_f
end
end
That will convert them to floats, e.g:
"1.61803399".to_f
=> 1.61803399
Edit:
Want a more declarative way? Just extend ActiveRecord::Base:
# config/initializers/ar_type_casting.rb
class ActiveRecord::Base
def self.cast_attribute(attribute, type_cast)
define_method attribute do
val = read_attribute(attribute)
val.respond_to?(type_cast) ? val.send(type_cast) : val
end
end
end
Then use it like this:
class Company < ActiveRecord::Base
cast_attribute :lat, :to_f
cast_attribute :lng, :to_f
end
Now when you call those methods on an instance they will be type casted to_f.
Following diego.greyrobot reply I modified my Company class with an additional method. It overrides the attributes method and afterwards typecast the needed fields. Yet something more declarative would be desirable imho.
class Company < ActiveRecord::Base
def attributes
retHash = super
retHash['lat'] = self.lat.to_f
retHash['lng'] = self.lng.to_f
retHash
end
end

DataMapper association

I'm trying to design a schema for an email solution so that I could access the incoming and sent messages on the User object using DataMapper. The associations "inbox" and "sent" don't do what's intended. What am I doing wrong? Thanks in advance!
I've the following so far (after reading a bit and copying the friends example from DM website) --
class User
include DataMapper::Resource
property :id, Serial
property :name, String, :required=>true
property :email, String, :required=>true, :unique=>true
property :password, String, :required=>true
has n, :messages, :child_key=>[:source_id, :target_id]
has n, :inbox, 'Message', :through=>:messages, :via=>:target
has n, :sent, 'Message', :through=>:messages, :via=>:source
end
class Message
include DataMapper::Resource
property :id, Serial
property :subject, String, :required=>true
property :body, String
belongs_to :source, 'User', :key=>true
belongs_to :target, 'User', :key=>true
end
I'm answering my own question -- hope it helps someone
The following change fixes the problem I've been having --
class User
...
has n, :inbox, 'Message', :child_key=>[:target_id]
has n, :sent, 'Message', :child_key=>[:source_id]
end
Everything else, remains the same...

DataMapper can't save to mysql and create object with id = nil

I am following the tinyclone example in Cloning Internet Application with Ruby and is trying to create an object to be stored into mysql.
However, whenever I try to create a Url object (see code below), the result is always
"=> Url #id=nil #original="http://www.gmail.com" #link_identifier=nil"
The id is not created nor the data is stored in the database. The link to the sql database is correct as I already tried dropping the database and recreating it using DataMapper.auto_migrate!
Can anyone help? Thanks.
DataMapper.setup(:default,'mysql://root#localhost/tinyclone')
class Url
include DataMapper::Resource
property :id, Serial
property :original, String, :length => 255
belongs_to :link
end
class Link
include DataMapper::Resource
property :identifier, String, :key => true
property :created_at, DateTime
has 1, :url
has n, :visits
end
DataMapper.finalize
url = Url.create(:original => 'http://www.gmail.com')
=> #<Url #id=nil #original="http://www.gmail.com" #link_identifier=nil>
In your Url model Link is a required association. You can't create a url without a link because validation will fail. If you want to be able to create urls without associating them with a link you can write belongs_to :link, :required => false

Mongoid, references_one, and HTML select

Here's a problem I'm having on a Rails 3 app...
I have a MedicalProfessional model that looks kind of like this:
class MedicalProfessional
include Mongoid::Document
include Mongoid::Timestamps
field :name, :type => String
references_one :medical_specialty
end
and a MedicalSpecialty model that looks like this:
class MedicalSpecialty
include Mongoid::Document
field :name, :type => String
validates_presence_of :name
referenced_in :medical_professional
end
In a view, I create an HTML select like so:
select("medical_professional", "medical_specialty", #specialties)
When posting that form, I'm getting the following error:
NoMethodError in Medical_professionals#create
Showing new.html.haml where line #27 raised:
You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.map
Line #27 is the one where I have the "select".
Any idea what the issue here is?
Your form post is failing, but the failed code path does not assign #specialties.

Problem with DataMapper, Integer property

I have the following class in my sinatra app (app.rb)
class Project
include DataMapper::Resource
property :id, Serial
property :creatorid, Integer, :key => false
property :name, String
end
Project.auto_migrate! unless Project.storage_exists?
and in the post method, I have:
project = Project.create
project.creatorid = GetLoggedInUserId() #returns an int
project.name = params['projectname']
But when I'm getting the following error:
no such column: creatorid (on the project.creatorid... line)
Suggestions?
You coult try with new method instead that create since latter one is used to generate and save an item on the go while the former one is used to generate an empty item that can be then filled (like you do) and then saved with project.save().
Take a look at documentation here..