Problem with DataMapper, Integer property - datamapper

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..

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

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

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

RoR - different object_id inside after_initialize callback after obj.reload

I've written a method for my project which extends ActiveRecord models behaviour, I've stripped out most of it, consider the following code:
class ActiveRecord::Base
def self.has_translations
after_initialize :clear_translations_cache
def clear_translations_cache
binding.pry
#_translations = {}
end
end
end
Basically, I want the #_translations instance variable to get cleared when I .reload the instance from the database, but for some reason, after fetching an existing object from the database, executing a method which populates #_translations, and then executing object.reload, #_translations still contains the same data.
I know for sure that the callback gets executed when first fetching the object from database and when calling .reload. I used binding.pry to halt execution inside the callback method, but for some reason self.object_id inside .reload has a different object_id than my original object, and therefore #_translations in the original object doesn't get cleared.
Attached is the console output:
1.9.3p194 :008 > s = TranslatedItem.first
76: def clear_translations_cache
=> 77: #_translations = {}
78: end
[1] pry(#<TranslatedItem>)> self.class
=> TranslatedItem(id: integer, created_at: datetime, updated_at: datetime)
[2] pry(#<TranslatedItem>)> self.object_id
=> 70254243993580
[3] pry(#<TranslatedItem>)> exit
1.9.3p194 :009 > s.object_id
=> 70254243993580
1.9.3p194 :010 > s.reload
76: def clear_translations_cache
=> 77: #_translations = {}
78: end
[1] pry(#<ServiceLevel>)> self.class
=> TranslatedItem(id: integer, created_at: datetime, updated_at: datetime)
[2] pry(#<TranslatedItem>)> self.object_id
=> 70254259259120
I'm guessing the behavior you're seeing is related to how ActiveRecord reload works:
fresh_object = self.class.unscoped { self.class.find(self.id, options) }
#attributes.update(fresh_object.instance_variable_get('#attributes'))
You'll notice that it is creating a fresh object by finding it from the database, which explains why you are seeing two different object_id values in your callback method. The object that is initialized during the reload is only used for its attributes and then goes out of scope.
It's not clear from your question whether you were just curious why it behaved this way or if you're looking for an alternative way to do it.
Update:
You've got a few options if you're just looking for a way to clear the instance variable when you reload the model.
1) Add your own reload method that you can explicitly call:
class ActiveRecord::Base
def reload_everything
reload
#_translations = {}
end
end
object.reload_everything
2) Change the behavior of reload
module ReloadTranslations
def reload(*args)
super
#_translations = {}
end
end
ActiveRecord::Base.send(:include, ReloadTranslations)

Neo4j::Rails::Model to_json - node id is missing

I have a Jruby on Rails application with Neo4j.rb and a model, let's say Auth, defined like this:
class Auth < Neo4j::Rails::Model
property :uid, :type => String, :index => :exact
property :provider, :type => String, :index => :exact
property :email, :type => String, :index => :exact
end
And this code:
a = Auth.find :uid => 324, :provider => 'twitter'
# a now represents a node
a.to_json
# outputs: {"auth":{"uid": "324", "provider": "twitter", "email": "email#example.com"}}
Notice that the ID of the node is missing from the JSON representation. I have a RESTful API within my application and I need the id to perform DELETE and UPDATE actions.
I tried this to see if it works:
a.to_json :only => [:id]
But it returns an empty JSON {}.
Is there any way I can get the ID of the node in the JSON representation without rewriting the whole to_json method?
Update The same problems applies also to the to_xml method.
Thank you!
I am answering my own question. I still think that there is a better way to do this, but, for now, I am using the following hack:
In /config/initializers/neo4j_json_hack.rb I put the following code:
class Neo4j::Rails::Model
def as_json(options={})
repr = super options
repr.merge! '_nodeId' => self.id if self.persisted?
end
end
And now every JSON representations of my persisted Neo4j::Rails::Model objects have a _nodeId parameter.
The ID is typically not included because it shouldn't be exposed outside the Neo4j database. Neo4j doesn't guarantee that the ID will be identical from instance to instance, and it wouldn't surprise me if the ID changed in a distributed, enterprise installation of Neo4j.
You should create your own ID (GUID?), save it as a property on the node, index it, and use that to reference your nodes. Don't expose the Neo4j ID to your users or application, and definitely don't rely on it beyond a single request (e.g. don't save a reference to it in another database or use it to test for equality).

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