How to store geocodes in Mongoid array with gmaps4rails - ruby-on-rails

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)

Related

Datatype validation in rails ActiveModel::Validations

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

Searchkick / Rails working example with Mongoid

I can't figure how to properly hook a view / form for searching through my docs with elasticsearch + mongoid.
My Searchkick config is working – I get the results inside the rails console. But I don't know exactly where to put things in what order in the controller/model/view to make it work. From the rails console I get the search results, docs are properly mapped and everything is fine.
I can't find a working example of an simple search form with searchkick including an working example of how a model, controller and a view should look like.
Anybody got an working example to checkout with Rails 4.1rc1 / Mongoid4 / Elasticsearch 1.0.1?
I've got rails 4.0.2, Mongoid4, and ElasticSearch >= 1
Anyway, this works for us in the controller:
class CropSearchesController < ApplicationController
def search
query = params[:q].to_s
#crops = Crop.search(query,
limit: 25,
partial: true,
misspellings: {distance: 2},
fields: ['name^20',
'common_names^10',
'binomial_name^10',
'description'],
boost_by: [:guides_count]
)
if query.empty?
#crops = Crop.search('*', limit: 25, boost_by: [:guides_count])
end
# Use the crop results to look-up guides
crop_ids = #crops.map { |crop| crop.id }
#guides = Guide.search('*', where: {crop_id: crop_ids})
render :show
end
end
And this is our model:
class Crop
include Mongoid::Document
include Mongoid::Timestamps
include Mongoid::Slug
searchkick
field :guides_count, type: Fixnum, default: 0
field :name
field :common_names, type: Array
validates_presence_of :name
field :binomial_name
field :description
belongs_to :crop_data_source
field :sun_requirements
field :sowing_method
field :spread, type: Integer
field :row_spacing, type: Integer
field :height, type: Integer
embeds_many :pictures, cascade_callbacks: true, as: :photographic
accepts_nested_attributes_for :pictures
def search_data
as_json only: [:name, :common_names, :binomial_name, :description, :guides_count]
end
slug :name
end
And then you just accesses the #crops in the view like you would normally.
You can have a look at our source code on github: https://github.com/openfarmcc/OpenFarm
(Just stumbled across this question while looking for how to do the ordering, figured it out, but thought I'd just copy paste this here in case anyone finds this useful).

limiting version attributes in mongoid

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

Mongoid named scope comparing two time fields in the same document

I need to create a named scope in Mongoid that compares two Time fields within the same document. Such as
scope :foo, :where => {:updated_at.gt => :checked_at}
This obviously won't work as it treats :checked_at as a symbol, not the actual field. Any suggestions on how this can be done?
Update 1
Here is my model where I have this scope declared, with a lot of extra code stripped out.
class User
include Mongoid::Document
include Mongoid::Paranoia
include Mongoid::Timestamps
field :checked_at, :type => Time
scope :unresolved, :where => { :updated_at.gt => self.checked_at }
end
This gives me the following error:
'<class:User>': undefined method 'checked_at' for User:Class (NoMethodError)
As far as I know, mongodb doesn't support queries against dynamic values.
But you could use a javascript function:
scope :unresolved, :where => 'this.updated_at >= this.checked_at'
To speed this up you could add an attribute like "is_unresolved" which will be set to true on update when this condition is matched ( and index that ).
scope :foo, :where => {:updated_at.gt => self.checked_at}
For example, this will work:
scope :foo, where(:start_date.lte=>Date.today.midnight)
Not sure if you'll like this method, it's not the best, but it should work.
class User
include Mongoid::Document
include Mongoid::Paranoia
include Mongoid::Timestamps
field :checked_at, :type => Time
scope :unresolved, lambda{ |user| where(:updated_at.gt => user.checked_at) }
end
You call it with User.unresolved(my_user_object)
It seems now after rereading your post that this probably won't do what you want. If this is true, then you will probably need to use MapReduce or possibly Baju's method (have not tested it)

how do I migrate Datamapper on appengine

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

Resources