I'm new to rails and in my project I have 2 classes who have a relationship betwen them. The problem is they dont can list services with organs. The following is the code I have:
modelos
class Admin::Organ
include Mongoid::Document
include Mongoid::Search
include Mongoid::Pagination
field :name, type: String
field :address, type: String
field :acronym, type: String
field :phones, type: String
field :emails, type: String
field :image, type: String
field :permalink, type: String
field :schedules, type: Array
field :coordinates, type: Hash
has_many :services, class_name: "Service"
has_many :units, class_name: "Admin::Unit"
before_save :touch_permalink
search_in :name
paginates_per 10
def url
"/orgao/#{permalink}"
end
private
def touch_permalink
self.permalink = self.name.parameterize
end
end
class Service
include Mongoid::Document
include Mongoid::Search
include Mongoid::Pagination
field :name, type: String
field :acronym, type: String
field :popular_names, type: Array
field :description, type: String
field :free, type: Boolean
field :applicants, type: Array
field :estimated_time, type: Hash
field :steps, type: Array
field :permalink, type: String
field :other_informations, type: String
belongs_to :organ, class_name: "Admin::Organ"
has_and_belongs_to_many :units, class_name: "Admin::Unit"
has_and_belongs_to_many :audiences, class_name: "Admin::Audience"
has_and_belongs_to_many :categories, class_name: "Admin::Category"
before_save :touch_permalink
search_in :name, :popular_names
paginates_per 10
def organ_id
read_attribute(:organ_id).to_s
end
def url
"/servico/#{permalink}"
end
private
def touch_permalink
self.permalink = self.name.parameterize
end
end
#controlers
class ServicesController < ApplicationController
def index
#organs = Admin::Organ.all
#services = Service.page(params[:page].to_i).per(3)
end
def show
#service = Service.where(permalink: params[:permalink]).first
end
end
class OrgansController < ApplicationController
def index
#organs = Admin::Organ.page(params[:page]).per(2)
end
def show
#organ = Admin::Organ.where(permalink: params[:permalink]).first
#organs = Admin::Organ.page(params[:page]).per(1)
end
end
#call in index.html
<%= organs.services.name%>
This appears to be returning an error whenever I run it
Note: On mongo relationships when you call a relationship method (such as services in your case) all of the documents associated with it are returned. Also for the pagination plugin you are using (I'm assuming kaminari by the syntax), this will return a collection of documents as well.
If so, it could be expected that you have a view for organs that has something a little like this:
<% #organs.each do |organ| %>
<div>Name: <%= organ.name %></div>
<div>Address: <%= organ.address %></div>
<div>Services:</div>
<% organ.services.each do |service| %>
<div>Name: <%= service.name %></div>
<div>Acronym: <%= service.acronym %></div>
<% end %>
<% end %>
<%= paginate #organs %>
You'll notice that to print out the services you need to first have a handle on the current document within #organs, and then you need to iterate the services within it. If you were to call name (which is a method of a relationship) you will get the relationship name (I believe this is what you are seeing).
I hope this helps. I had to do some guessing between the lines, come back to me if you need any further help.
Related
I use Ruby on rails and mongoid.
I have two models User.rb and Project.rb. If I want to change owner of Project model, how should I do this?
User.rb
class User
include Mongoid::Document
field :name, type: String
has_many :projects, dependent: :destroy
end
Project.rb
class Project
include Mongoid::Document
field :title, type: String
validates :user_id, presence: true
belongs_to :user, touch: true
end
in form.html.erb i have select mode
<div class="form-group">
<%= f.collection_select :user_id, User.all, :id, :name, class: 'form-control' %>
</div>
you should be able to just assign it to the user field and then save it to persist it to the database
project = Project.find(project_id)
new_owner = User.find(new_owner_id)
project.user = new_owner
project.save
i did not use mongoid long time ago, but you can try running these commands on your rails console:
project.user = owner_object;
project.save
OR
project.user_id = owner_id
project.save
I have an application where users can create many travels, and they can invite their facebook friends. In the travel document, there is a field "participants" that is an embedded document, Participant model embedded in Travel model.
Here are my models :
class Travel
include Mongoid::Document
include Mongoid::Timestamps
# relations
belongs_to :user
# fields
field :title, type: String
field :description, type: String
field :begin_date, type: Date
field :end_date, type: Date
field :budget, type: Integer
field :go_back, type: Boolean
field :title_namespace, type: String
# friends
embeds_many :participants
accepts_nested_attributes_for :participants
end
class Participant
include Mongoid::Document
include Mongoid::Timestamps
field :name, type: String
field :user_id, type: String
# relations
embedded_in :travel, :inverse_of => :participants
end
When I try to display travel where users have been invited, with this request :
#travel_participations = Travel.where('participants.user_id' => #user.id)
I don't have any result, even if I have this line in byebug :
#<Mongoid::Criteria
selector: {"participants.user_id"=>BSON::ObjectId('592c8da58511989ec850921e')}
options: {}
class: Travel
embedded: false>
So when I put this on my view :
<% unless #participations.nil? %>
<% #travel_participations.each do |travel_participation| %>
<p> <%= travel_participation.title %> </p>
<% end %>
<% end %>
I tried with .all, .first, .to_a, .as_json, no results ... Some one know where is the problem ?
You have this in your embedded model:
field :user_id, type: String
but your query is using a BSON::ObjectId:
Travel.where('participants.user_id' => #user.id)
as shown in the raw query:
selector: {"participants.user_id"=>BSON::ObjectId('592c8da58511989ec850921e')}
Your embedded document probably has a string field like:
"user_id": "592c8da58511989ec850921e"
rather than the ObjectId you're looking for:
"user_id": ObjectId("592c8da58511989ec850921e")
so you won't find what you're looking for due to the type mismatch.
Either fix the embedded field's type:
field :user_id, type: BSON::ObjectId
or query it as the string it is:
Travel.where('participants.user_id' => #user.id.to_s)
Changing the type will involve fix up whatever data you already have, changing the query is ugly in a different way.
Sometimes Mongoid will convert between strings and ObjectIds for you, sometimes it won't. When I used Mongoid I patched to_bson_id methods into BSON::ObjectId, String, Mongoid::Document, ... so that I could say things like:
Model.where(:some_id => some_id.to_bson_id)
and not have to constantly worry about what type some_id was. I also made sure that all ID fields were always specified as BSON::ObjectId.
I have 3 models source.rb belongs to category.rb and feed_entry.rb belongs to source.rb.
I need to display feed_entries in category
Category name
FeedEntry 1
FeedEntry 2
FeedEntry 3
Now it looks like this
class CategoriesController < ApplicationController
def show
#category = Category.find(params[:id])
#sources = #category.sources.all
end
end
show.html.erb
<%= #category.name %></h4>
<% #sources.each do |source| %>
<% source.feed_entries.each do |feed_entry| %>
<%= link_to feed_entry.name, feed_entry %>
<%= feed_entry.source.title %>
<% end %>
<% end %>
this is very slow
I use mongoid 4, rails 4
Models
class Category
include Mongoid::Document
field :name, type: String
has_many :sources, dependent: :destroy
end
class FeedEntry
include Mongoid::Document
field :name, type: String
belongs_to :source, touch: true
validates :source_id, presence: true
end
class Source
include Mongoid::Document
field :title, type: String
has_many :feed_entries, dependent: :destroy
belongs_to :category, touch: true
end
Some thinks to know :
Never use .all, unless you know size of result data. Always use pagination or limit.
When you have a loop like your each in view, this will call queries like this :
Give me a category
Give me its sources
Give me feed entries for source 1
Give me feed entries for source 2
....
You should eagler load your association like this :
#sources = #category.sources.limit(20).includes(:feed_entries)
It will to theses queries :
Give me a category
Give me its sources
Give me feed entries for theses sources
If you don't want any information about categories (like I think), you should add a relation to your model :
Class Category
has_many :sources
has_many :feed_entries, :through => :sources
end
Then call in your controller
#feed_entries = #category.feed_entries
This will do only ONE query :
Give me category
Give me the feed entries of the category
That's it !
I found a solution:
In Category.rb add feed_entries
class Category
def feed_entries
FeedEntry.in(source_id: sources.map(&:id))
end
end
and in show.html.erb
<% #category.feed_entries.includes(:source).each do |feed_entry| %>
<%= link_to feed_entry.name, feed_entry %>
<%= feed_entry.source.title %>
<% end %>
I have a model Line Items embedded in Line model. In Line create view, I have provided ability to define multiple nested levels of line items.
Here is a random snap of param[:line]:
=> {"title"=>"Hello", "type"=>"World", "line_items"=>{"1"=>{"name"=>"A",
"position"=>"1", "children"=>{"1"=>{"name"=>"A1", "position"=>"1",
"children"=>{"1"=>{"name"=> "A11", "position"=>"1"}, "2"=>{"name"=>"A12",
"position"=>"2"}}}, "2"=>{"name"=>"A2", "position"=>"2"}}}, "3"=>
{"name"=>"B", "position"=>"3"}}}
In Line#create, I have:
def create
#line = Line.new(params[:line])
if #line.save
save_lines(params[:line][:line_items])
flash[:success] = "Line was successfully created."
redirect_to line_path
else
render :action => "new"
end
end
In Line#save_lines, I have:
# Save children up to fairly infinite nested levels.. as much as it takes!
def save_lines(parent)
unless parent.blank?
parent.each do |i, values|
new_root = #line.line_items.create(values)
unless new_root[:children].blank?
new_root[:children].each do |child|
save_lines(new_root.children.create(child))
end
end
end
end
end
LineItem Model looks like:
class LineItem
include Mongoid::Document
include Mongoid::Timestamps
include Mongoid::Ancestry
has_ancestry
# Fields
field :name, type: String,
field :type, type: String
field :position, type: Integer
field :parent_id, type: Moped::BSON::ObjectId
attr_accessible :name, :type, :url, :position, :parent_id
# Associations
embedded_in :line, :inverse_of => :line_items
end
in Line model, i have:
# Associations
embeds_many :line_items, cascade_callbacks: true
Which work as expected. But, is there a better way to save the line_items recursively with Ancestry?
I think your code looks fine. I just refactored it.
How about:
def save_lines(parent)
parent.each do |i, values|
#get children hash if any
children = values.delete("children")
# create the object with whatever remain in values hash
#line.line_items.create(values)
# recurse if children isn't empty
save_lines(children) if children
end
end
I am following this video http://railscasts.com/episodes/258-token-fields-revised and i implement this also sucessfully. But now i am using namespace.
I have lends_controller inside folder employee inside asset folder.
this is my model of lend controller
class Employee::Asset::Lend
include Mongoid::Document
include Mongoid::Timestamps
field :name, type: String
field :text, type: String
field :date
field :asset_tokens
field :user_id, type: String
has_and_belongs_to_many :assets
belongs_to :tags
def asset_tokens=(tokens)
self.asset_ids = Asset.ids_from_tokens(tokens)
end
end
Now i have another model asset. There i have to define has and belongs to this lend model also I did this
class Asset
include Mongoid::Document
field :name, type: String
field :description, type: String
field :serial_number, type: String
field :status, type: Integer
field :tag_tokens
field :quantity, type: Integer
validates_presence_of :name
validates :serial_number,:uniqueness => true
has_and_belongs_to_many :employee_asset_lends
has_and_belongs_to_many :tags
def self.tokens(query)
assets = where(name: /#{Regexp.escape(query)}/i)
end
form for lend controller is
<%= f.label :asset_tokens, "Assets" %>
<%= f.text_field :asset_tokens, data: {load: #employee_asset_lend.assets}%><br>
<%= f.input :date,:input_html => { :class => "dp1"},:label=> "Lend Date"%>
inside coffescript file for lend.js.coffee
jQuery ->
$('#employee_asset_lend_asset_tokens').tokenInput '/assets.json'
theme: 'facebook'
prePopulate: $('#employee_asset_lend_asset_tokens').data('load')
But it gives error uninitialized constant EmployeeAssetLend from asset views.
and from lend view it gives error like undefined methodall_of' for Employee::Asset:Module`
pleaes check the right way to make HABTM-has_and_belongs_to_many Assosiation for more details