recursively_embeds_many not persisting - mongoid

I have a really simple model
class Region
include Mongoid::Document
recursively_embeds_many
field :name, type: String
end
I can assign a parent and it seems to work, but the data doesn't persist after saving.
> region1.parent_region = region2
> region2.child_regions
[region1]
> region1.save
> Region.find(region1._id).parent_region
nil
What am I doing wrong?

Related

Mongoid query with where clause on an association of an embeded document

I have a Rails app using Mongoid with the classes User, ContractAgreement and ContractVersions.
The relationships are the following: User embeds ContractAgreement, and ContractAgreement belong to ContractVersions, like so:
User:
class User
include Mongoid::Document
include Mongoid::Stateful
include Mongoid::Timestamps
[...]
embeds_many :contract_agreements
ContractAgreement:
class ContractAgreement
include Mongoid::Document
include Mongoid::Timestamps
embedded_in :user
belongs_to :contract_version
field :date_of_agreement, type: DateTime
ContractVersion
class ContractVersion
include Mongoid::Document
include Mongoid::Timestamps
field :version, type: String
field :description, type: String
field :status, type: String
has_one :post, autosave: true
has_one :post, autosave: true
#has_many :contract_agreements
As you can see, #has_many :contract_agreements is commented out as Mongoid didn't like the association to an embeded document.
Is there a way of getting the list of Users that have agreed to a specified contract?
I've tried both doing $elemMatch all the way:
[64] pry(main)> reload!;
u = User.all.select{|u| u.contract_agreements.count > 0}.first ;
cv = u.contract_agreements.first.contract_version ;
User.where(contract_agreements: {'$elemMatch' => {contract_version: {'$elemMatch' => {_id: cv._id}}}}).count
Reloading...
=> 0
As well as the compressed single query notation:
[64] pry(main)> reload!;
u = User.all.select{|u| u.contract_agreements.count > 0}.first ;
cv = u.contract_agreements.first.contract_version ;
User.where("contract_agreements.contract_version._id" => cv._id).count
Reloading...
=> 0
I know the contract version id I am asking for exists since I explicitly select a user that has one.
Is such a query even possible or do I need to de-embed ContractAgreement? If it is possible, what am I doing wrong?
Referring to the foreign key worked:
[73] pry(main)> reload!;
u = User.all.select{|u| u.contract_agreements.count > 0}.first ;
cv = u.contract_agreements.first.contract_version ;
User.where("contract_agreements.contract_version_id" => cv._id).count
Reloading...
=> 1

Validating array insertion in Rails

I have Table1 with attribute attribute1, which is an array of integer. My controller allows for one insertion at a time. So, in the controller:
def add_attribute1_item
table1 = Table1.find(params[:id])
table1.attribute1 << add_params[:attribute1_item]
table1.save!
render json: table1
rescue
render_errors_for(table1)
end
I want to validate this attribute1_item value, ignoring the old values that have been stored in attribute1 array, e.g. if table1.attribute1 contains 99 and I call the controller add_attribute1_item to add 100, I only want to check whether 100 is valid or not, ignoring 99.
class Task < ApplicationRecord
.
.
.
validate :attribute1_item_is_valid, if: -> { attribute1.present? }
.
.
.
def attribute1_item_is_valid
# validate the item by accessing attribute1
end
I am unsure with this approach because when I access attribute1 in attribute1_item_is_valid, it is the whole array instead of the new item. Is this approach good enough by calling attribute1.last() or is there a more correct method?
thank you
Instead of trying to validate this in the model, validate the form entry.
Create a model for the form and use normal validations.
class SomeForm
include ActiveModel::Model
attr_accessor :id, :attribute1_item
validate :id, presence: true, numericality: { only_integer: true }
validate :attribute1_item, presence: true
end
def add_attribute1_item
form = SomeForm.new(params)
if form.invalid?
# render form.errors
return
end
table1 = Table1.find(form.id)
table1.attribute1 << form.attribute1_item
table1.save!
render json: table1
rescue
render_errors_for(table1)
end

Implementing union type with graphql-ruby

I'm trying to implement a union type with graphql-ruby.
I followed the official documentation but got the error listed below.
Here is my current code.
module Types
class AudioClipType < Types::BaseObject
field :id, Int, null: false
field :duration, Int, null: false
end
end
module Types
class MovieClipType < Types::BaseObject
field :id, Int, null: false
field :previewURL, String, null: false
field :resolution, Int, null: false
end
end
module Types
class MediaItemType < Types::BaseUnion
possible_types Types::AudioClipType, Types::MovieClipType
def self.resolve_type(object, context)
if object.is_a?(AudioClip)
Types::AudioClipType
else
Types::MovieClipType
end
end
end
end
module Types
class PostType < Types::BaseObject
description 'Post'
field :id, Int, null: false
field :media_item, Types::MediaItemType, null: true
end
end
And here is the graphql query.
{
posts {
id
mediaItem {
__typename
... on AudioClip {
id
duration
}
... on MovieClip {
id
previewURL
resolution
}
}
}
}
When I send the query I got the following error.
Failed to implement Post.mediaItem, tried:
- `Types::PostType#media_item`, which did not exist
- `Post#media_item`, which did not exist
- Looking up hash key `:media_item` or `"media_item"` on `#<Post:0x007fb385769428>`, but it wasn't a Hash
To implement this field, define one of the methods above (and check for typos
Couldn't find any typo or anything.
Am I missing something??
You didn't define parent type (superclass of your union).
So add
class Types::BaseUnion < GraphQL::Schema::Union
end
Now your inheritance chain will consistent.

Validating relationships invalids in mongoid

class A
include Mongoid::Document
field :value, type: String
validates :value, presence: true
has_and_belongs_to_many :cs
end
class B
include Mongoid::Document
belongs_to :a
embedded_in :c
end
class C
include Mongoid::Document
embeds_many :bs
end
:
c = C.create #<C _id: 53c96d1f05dfd40943000001, >
c.valid? # true
a = A.create #<A _id: 53c96d8305dfd4b6e1000002, value: nil, c_ids: nil>
a.valid? # false
invalid_b = c.bs.create(a: a) #<B _id: 53c96dac05dfd4b6e1000004, a_id: "53c96d8305dfd4b6e1000002">
# Invalid object has created !!!!!
# a not been persisted but the c saved his id.
invalid_b.reload
invalid_b.a # nil
invalid_b.a_id # 53c96d8305dfd4b6e1000002
The "a" field is not valid yet "b" is being created.
How can I solve this problem?
So that the class "B" to validate the field before saving?
if you used
invalid_b = c.bs.create!(a: a)
instead of
invalid_b = c.bs.create(a: a)
the invalid record won't create and the create! will raise Mongoid::Errors::Validations exception
check http://mongoid.org/en/mongoid/docs/persistence.html for reference

mongoid, embedy_many, simple_form

i m looking for a way to manage multiple embedded objects in a form.
found a solution for formtastic by bowsersenior
Formtastic with Mongoid embedded_in relations
but i wasnt able to do the same for simple_form
formtastic:
= semantic_form_for #team do |form|
= #team.players.each do |player|
= form.inputs :for => [:players, player] do |player_form|
= player_form.input :name
best regards
sample
class Team
include Mongoid::Document
field :name, :type => String
embeds_many :players
end
class Player
include Mongoid::Document
embedded_in :team, :inverse_of => :players
field :name, :type => String
field :active, :type=> Boolean # checkboxes
end
Not sure if this would work but you might want to try something like this:
= simple_form_for #team do |form|
= f.input :name
= f.simple_fields_for #team.players do |player_form|
= player_form.input :name
Just keep in mind that you will have to create a new player in the team before the form will show up.
In your controller(controller):
def new
#team = Team.new
8.times { #team.players.new } #for 8 players
end

Resources