I've changed my model from
class Place
include DataMapper::Resource
has n, :trails
property :id, Serial
property :name, String, :length => 140
property :tag, String, :required => true
timestamps :at
end
to
class Place
include DataMapper::Resource
has n, :trails
property :id, Serial
property :name, String, :length => 140
property :tag, String, :required => true
property :trail_count, Integer, :default => 0
timestamps :at
end
I just added "property :trail_count, Integer, :default => 0"
and i want to migrate the existing appengine table to have the extra field "trail_count"
i've read that DataMapper.auto_upgrade! should do it.
but i get an error "undefined method `auto_upgrade!' for DataMapper:Module"
can you please help How do i migrate the DM models?
After restarting the server for the third time the field was miraculously added.
It's still a weird and not so good way to do migrations.
how do you manipulate data without migrations? like splitting a field "full name" to first and last name fields? you gotta have a migration for that..
I've been looking up the same issue Roy and it appears migrations don't work on app engine using datamapper (or any other interface). It's a function of the datastore, and to update existing database entries you'll have to query the database and update a few at a time to avoid hitting rate limits.
source
Try requiring the dm-migrations gem. This was how I resolved the issue with Sinatra 1.4.7 and do_sqlite3 0.10.17.
require 'dm-migrations'
require 'rubygems'
require 'sinatra'
require 'dm-core'
require 'dm-timestamps'
require 'dm-sqlite-adapter'
require 'dm-migrations'
DataMapper::setup(:default, "sqlite3://#{Dir.pwd}/adserver.db")
class Ad
include DataMapper::Resource
property :id, Serial
property :title, String
property :content, Text
property :width, Integer
property :height, Integer
property :filename, String
property :url, String
property :is_active, Boolean
property :created_at, DateTime
property :updated_at, DateTime
property :size, Integer
property :content_type, String
end
# Create or upgrade all table at once, like magic
DataMapper.auto_upgrade!
answer found here
Related
I wanted to validate class attributes with respect to their data type.
I am writing an API in ruby and i need to check if a particular parameter data is of type String, hash, Array etc.
eg.
we have
class ApiValidation
include ActiveModel::Validations
attr_accessor :fieldName
validates :fieldName, :presence => true
end
so similar to :presence => true, i want to add one more validation like :datatype => :string
Please suggest me some custom validation or any other approach to achieve my requirement.
You can check out dry-rb stack.
There is https://github.com/dry-rb/dry-types (https://dry-rb.org/gems/dry-types/1.2/) gem which do exactly what you want.
From docs:
Strict types will raise an error if passed an attribute of the wrong type:
class User < Dry::Struct
attribute :name, Types::Strict::String
attribute :age, Types::Strict::Integer
end
User.new(name: 'Bob', age: '18')
# => Dry::Struct::Error: [User.new] "18" (String) has invalid type for :age
In Ruby, "datatypes" are actually just classes. So, all you really have to do is check which class fieldName belongs to (fieldName.class) in your custom validation.
Parameters are always received as text. Ruby doesn't have static types, but it does have classes, so your code needs to parse each attribute and convert them into the class you expect.
This could be as simple as riding on Ruby's inbuilt conversion methods, eg. to_i, to_sym, to_d, to_h, or you might need to add more logic, eg. JSON.parse.
Do note the difference between strict and non-strict parsing which will require different control flow handling.
>> "1one".to_i
=> 1
>> Integer("1one")
ArgumentError: invalid value for Integer(): "1one"
According to the Rails Guides and Rails API docs, we could use validates_each method which is available in ActiveModel::Validations.
For example:
class Person
include ActiveModel::Validations
attr_accessor :first_name, :last_name
validates_each :first_name, :last_name do |record, attr, value|
record.errors.add attr, " must be a string." unless value.is_a? String
end
end
I am able to use the basic map display capabilities in gmaps4rails with mongoid, which is great, but Im falling short with more advanced features. I think I am missing some basics and looking for guidance.
I am able to get the basic geocoding to work with fields named :latitude :longitude and :gmaps but when I try to use an array, as suggested by the readme, I am getting nowhere. I've read the Mongoid tips in the wiki to no avail.
Can anyone point me in the right direction?
Update;
Since Ive gotten no responses, here is some code examples,
The Model
working;
class Account
include Mongoid::Document
include Gmaps4rails::ActsAsGmappable
acts_as_gmappable
field :account_no
field :owner_name
field :address
field :latitude, :type => Float
field :longitude, :type => Float
field :gmaps, :type => Boolean
def gmaps4rails_address
"#{self.address}"
end
end
Not working
class Account
include Mongoid::Document
include Gmaps4rails::ActsAsGmappable
acts_as_gmappable :position => :location
field :account_no
field :owner_name
field :address
field :location, :type => Array
def gmaps4rails_address
"#{self.address}"
end
end
Based on the code snippets in the gmaps4rails readme this should work to geocode the address into the location array but I get this error
NoMethodError: undefined method `gmaps' for #<Account:0x007fc47d051ba0>
As explained here, gmaps is a boolean which purpose is to prevent multiple geocoding of the same address.
So the field is necessary, unless you tell it explicitly (see same doc)
I'm using Mongoid::Versioning which works great except that I would like to prevent several fields from being versioned.
There's not a lot of info written about it in the docs so I'm not sure how to do this.
http://mongoid.org/docs/extras.html
class Person
include Mongoid::Document
include Mongoid::Versioning
# keep at most 5 versions of a record
max_versions 5
end
They show how to skip a version altogether but not how to restrict certain fields from being versioned.
Any ideas?
UPDATE
I found something like this digging through the code, but I'm not sure how to use it.
https://github.com/mongoid/mongoid/blob/master/lib/mongoid/versioning.rb#L90
All Field has option :versioned true by default If you don't want this versionned you can pass false. By exemple I want name versioned but no login
class User
include Mongoid::Document
include Mongoid::Versioning
field :name, :type => String
field :login, :type => String, :versioned => false
end
You can pass the :versioned option in embed association too.
You can override this option by iterating over the .fields on your Document.
So in your code you can add avoid versionned on some field by creating a little methode :
class User
include Mongoid::Document
include Mongoid::Versioning
include Mongoid::Voteable
field :name, :type => String
field :login, :type => String
def self.avoid_versioned(*unversioned_fields)
unversioned_fields.each do |f|
fe = self.fields[f.to_s]
fe.options[:versioned] = false if fe
re = self.relations[f.to_s]
re[:versioned] = false if re
end
end
avoid_versioned( :login, :votes )
end
You can probably find a way to do this, but I would suggest checking out this gem instead.
https://github.com/aq1018/mongoid-history
track_history :on => [:title, :body], # I want to track title and body fields only. Default is :all
:modifier_field => :modifier, # Adds "referened_in :modifier" to track who made the change. Default is :modifier
:version_field => :version, # Adds "field :version, :type => Integer" to track current version. Default is :version
:track_create => false, # Do you want to track document creation? Default is false
:track_update => true, # Do you want to track document updates? Default is true
:track_destroy => false, # Do you want to track document destruction? Default is false
You may skip versioning at any point in time by wrapping the persistence call in a versionless block.
class Person
include Mongoid::Document
include Mongoid::Versioning
end
person.versionless do |doc|
doc.update_attributes(name: "Theodore")
end
I'm getting the error "undefined method 'timestamps!' when using Rails 3 with MongoMapper and was wondering if anyone can help resolve this problem.
I'm using Rails 3.0.1, mongo_mapper 0.8.6, and mongo 1.1
My model:
class User
include MongoMapper::EmbeddedDocument
key :_id, String
key :name, String, :required => true, :limit => 100
key :email, String, :required => false, :limit => 200
key :bio, String, :required => false, :limit => 300
timestamps!
end
First off, I'll note that if you're using Rails 3, you might want to look at Mongoid. It uses ActiveModel so you get all the Rails 3 polish with it. I prefer MongoMapper for 2.3.x projects, but Mongoid has seemed much more stable for me in Rails 3 projects.
That said, the timestamps! method is provided by the Timestamps plugin, which should be loaded as a part of the MongoMapper::Document inclusion. However, you could try including it manually:
class User
include MongoMapper::Document
plugin MongoMapper::Plugins::Timestamps
timestamps!
end
If the timestamps module isn't being loaded for any reason, that should manually include it in your model, and should make it available for use.
I have a datamapper model that has a unique index on a property called name. I want to create new records when a name doesn't already exist and silently ignore attempts to create records with duplicate names. What's the "right" way to do this in datamapper?
The best approach is to use the dm-validations gem, and ensure that your name property is specified as being unique, eg:
class Committer
include DataMapper::Resource
# ... other properties ...
property :name, String, :length => 1..100, :required => true, :unique => true
end
The dm-validations gem will introspect your model and automatically setup validations for your properties. In this case it won't allow more than one Committer to have the same name.
I think the best answer is to use first_or_create, which as Dan points out above, is already built into datamapper and therefore doesn't need to be declared.
require 'dm-core'
require 'dm-validations'
class Committer
include DataMapper::Resource
property :id, Serial
property :name, String, :unique_index => true
validates_present :name
validates_is_unique :name
end
committer = "George"
record = Committer.first_or_create(:name => committer)
One solution I came up with is simply to ignore the exception:
begin
Committer.create!(:name => committer)
rescue DataObjects::IntegrityError => e # ignore duplicate inserts
end
If you have a better (more idiomatic) way of doing it, please let me know.
Here is another solution I came up with:
require 'dm-core'
require 'dm-validations'
require 'dm-more'
record = Committer.find_or_create(:name => committer)
If you're using this in sinatra, requiring dm-more seems to cause
other problems. My solution was to require my own file that only
contained the following code:
module DataMapper
module Model
def first_or_create(conditions = {}, attributes = {})
first(conditions) || create(conditions.merge(attributes))
end
alias find_or_create first_or_create
end
end