Mongo, Mongoid join data from different models in Ruby on Rails - ruby

I'm adapting a Ruby on Rails application to work with MongoDB instead of PostgreSQL. I have this 2 class:
module Cms
class Content
include Mongoid::Document
include Mongoid::Orderable
field :title, type: String
field :position, type: String
field :text_body, type: String
field :expiration_date, type: Date
field :active, type: Boolean, default: false
validates :title, :text_body, presence: true
orderable base: 0
belongs_to :cms_content_category, class_name: 'Cms::ContentCategory'
scope :ordered, ->() { order(position: :asc) }
scope :not_expired, ->() { any_of({ expiration_date: nil }, { :expiration_date.gte => Date.today }) }
end
end
module Cms
class Submenu
include Mongoid::Document
include Mongoid::Orderable
field :title, type: String
field :position, type: String
field :external_url, type: String
field :open_as, type: String, default: '_self'
field :active, type: Boolean, default: false
delegate :url_helpers, to: :'Rails.application.routes'
validates :title, presence: true
validates :external_url, presence: true, if: Proc.new { |obj| obj.cms_content_id.nil? }
validates :cms_content_id, presence: true, if: Proc.new { |obj| obj.external_url.blank? }
orderable base: 0
belongs_to :cms_content, class_name: 'Cms::Content'
belongs_to :cms_menu, class_name: 'Cms::Menu'
scope :ordered, ->() { order(position: :asc) }
def url
self.external_url.present? ? self.external_url : url_helpers.content_show_path(self.cms_content_id)
end
end
end
The problem is that I don't know how to adapt the following SQL query to work with MongoDB.
scope :active, joins("FULL JOIN contents ON contents.id = cms_submenus.content_id")
.where("cms_submenus.active IS TRUE AND (
(cms_submenus.content_id IS NOT NULL AND ((contents.expiration_date >= :today OR expiration_date IS NULL) AND contents.archived IS NOT TRUE)) OR
(cms_submenus.external_url IS NOT NULL AND cms_submenus.external_url <> '')
)", today: Date.today)
This scope has to be called from Submenu model.
Someone has an idea on how to solve this problem?
I'm using Rails 4.2.0 with Ruby 2.2.0 and Mongoid 4.0.2 with MongoDB 2.6.8.
thank you

Related

Create a foreign key using belongs_to between two mongoid collections

There are two classes.
First class
class Baby
include Mongoid::Document
field :first_name, type: String
field :surname, type: String
field :dob, type: Integer
belongs_to :parent, foreign_key: :username
validates :parent, :presence => true
end
Second class
class Parent
include Mongoid::Document
field :username, type: String
field :first_name, type: String
field :surname, type: String
field :email, type: String
field :password, type: String
has_many :baby
end
When I create a new instance of the Baby class, I pass in a username. This should correlate to a username in the Parent document. Effectively storing a relation between the Baby and the Parent.
Baby.create!(first_name: 'James', surname: 'Barr', dob: '17-09-2012', username: 'foo123')
I keep getting this every time:
Mongoid::Errors::Validations:
message:
Validation of Baby failed.
summary:
The following errors were found: Parent can't be blank, Parent can't be blank
resolution:
Try persisting the document with valid data or remove the validations.

Validation doesn't work in "sexy" style

It seems that Rails doens't let me pass in more than one parameter when using this validation syntax. It always has a syntax method for an unexpected comma after the first argument.
class Apartment < ActiveRecord::Base
geocoded_by :location
after_validation :geocode
has_many :image_attachments
validates_associated :image_attachments
accepts_nested_attributes_for :image_attachments
validates :location, presence: true
validates :description, presence: true
validates :price, :presence => true
,:format => { with: /^[0-9]+$/, message: 'must be a number' }
validates :longitude, presence: true
end
It's bad formatting (and very "unsexy") to have the comma at the beginning of the next line.
Better to do...
validates :price, :presence => true,
:format => { with: /^[0-9]+$/, message: 'must be a number' }
...which should work fine.
A more consistent style is to use the Ruby 1.9 convention for key/value when key is a symbol.
validates :price, presence: true,
format: { with: /^[0-9]+$/, message: 'must be a number' }

Unable to create correct Mongoid model from JSON

I'm trying to create a Mongoid model from the corresponding JSON structure.
However it does not include the embedded relation frameworks.
I'm using Mongoid 4.0. Am I doing something wrong or is this a bug?
If I store any embedded relation via store_as under a different name than the default serialization, it works as expected. Also, if I create the model in the database from JSON rather than initialize it everything's fine...
JSON input
{
"name": "MyName",
"frameworks": [
{
"name": "grails",
"runtime": "groovy",
"versions": []
}
]
}
Models
require 'mongoid'
class Vendor
include Mongoid::Document
include Mongoid::Attributes::Dynamic
# fields
field :name, type: String
# relations
embeds_many :frameworks
# validations
validates :name, presence: true
validates :frameworks, presence: true
end
class Framework
include Mongoid::Document
embedded_in :vendor
field :name, type: String
field :runtime, type: String
field :versions, type: Array
# validations
validates :name, presence: true
validates :runtime, presence: true
end
Test App
require 'json'
require 'require_relative'
require_relative 'vendor'
begin
json = JSON.parse(File.read('input.json'))
#profile = Vendor.new(json)
puts #profile.inspect
rescue JSON::ParserError => e
puts "Error: " << e.to_s
end

Mongo object's id as uploadings dirname in CarrierWave

I'm using Sinatra with Mongoid and CarrierWave. I need to store document's attachments in /public/attachments/DOCUMENTS_ID.
Model of Mongo document:
class Dcmnt
include Mongoid::Document
store_in collection: 'dcmnts'
field :published, type: Boolean
field :name, type: String
field :description, type: String
field :additional, type: String
field :created_at, type: Date
mount_uploader :attachment, Uploader, type: String
end
And action's code:
post '/admin/create' do
params.delete 'submit'
d = Dcmnt.new(
:published => params[:published],
:name => params[:name],
:description => params[:description],
:additional => params[:additional],
:created_at => Time.now
)
d.attachment = params[:photos]
d.save
end
When I'm setting up unloader like this:
class Uploader < CarrierWave::Uploader::Base
storage :file
def store_dir
'public/attachments/' + d.id
end
end
It doesn't works for some amzaing reason. Can you help me implement this feature?
Accessing models attributes in CarrierWave is provided via model key word
class Uploader < CarrierWave::Uploader::Base
storage :file
def store_dir
'attachments/' + model.id
end
end

Mongoid: filtering an embedded collection by sub-sub-documents multiple fields

I am a beginner in mogo and mongoid.
I it possible to filter sub-documents collection by a sub-sub-documents multiple fields ($elemMatch)? I'm trying to make a parametrized scope for an embedded collection.
Set up:
class Product
include Mongoid::Document
include Mongoid::Timestamps
field :name, type: String, default: ''
embeds_many :versions, class_name: self.name, validate: false, cyclic: true
embeds_many :flags
end
class Flag
include Mongoid::Document
include Mongoid::Timestamps
field :text, type: String
field :state, type: Boolean
end
Typically now i want to filter my versions within single product by flags state and name:
Product.first.versions.where('$elemMatch' => {'flags.text' => 'normalized', 'flags.state' => true}) dosn't work.
Either don't work:
Product.first.versions.elem_match(flags: {text: 'normalized', state: true})
Product.first.versions.where(:flags.elem_match => {text: 'normalized', state: true})
Product.first.versions.where(flags: {'$elemMatch' => {text: 'normalized', state: true}})
Is there a way to do this? Thanks.

Resources