Rails 5 - Mongoid - Concerns - ruby-on-rails-5

I'm trying to abstract generic functions to a model concern on a Rails 5 with Mongoid app. This is the first app I do with mongoid and with other projects I had no problems implementing the next:
movie.rb
class Movie
include Mongoid::Document
include Genericable
field :name, type: String
field :year, type: Date
field :length, type: Integer
field :writers, type: Array
validates_presence_of :name, :year, :length
validates_uniqueness_of :name
index({name: 1}, {unique: true})
has_many :writers, class_name: "Person"
embeds_many :roles, class_name: "MovieRole"
end
genericable.rb (concern)
module Genericable
extend ActiveSupport::Concern
def self.s
all.map{|x| x}
end
end
(Methods are for demonstration purposes only).
When I try, on my rails console Movie.s I get next error:
NoMethodError: undefined method `s' for Movie:Class
Any clue about what I'm doing wrong? Thanks in advance for any help.

Related

Undefined method "id" trying to save nested attributes in the same form

I am developing a web application with Rails in which I need to save two models with the same form. One of the models (Characteristic) belongs to the other (Facilities), so I decided to use a accepts_nested_attributes_for for the contained model. In the view, I use form_for to save the parent model (Characteristic) and another form_for for the contained model (Facilities). However, I always obtain the same error:
Started PUT "/facilities/537f8adfb4f2d7c124000056" for 127.0.0.1 at 2014-05-31 20:00:23 +0200
Processing by FacilitiesController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"xr+cGlb9onx4o13IaS3K5UfYzmrb6pMdKljBc8byKdY=", "facilities"=>{"description"=>"Services", "characteristics"=>[{"id"=>"537f8adfb4f2d7c124000057", "title"=>"Room", "description"=>"Free"}]}, "commit"=>"Send", "id"=>"537f8adfb4f2d7c124000056"}
MOPED: 127.0.0.1:27017 COMMAND database=admin command={:ismaster=>1} (1.2872ms)
MOPED: 127.0.0.1:27017 QUERY database=hotel_abadi_development collection=facilities selector={"_id"=>"537f8adfb4f2d7c124000056"} flags=[:slave_ok] limit=0 skip=0 batch_size=nil fields=nil (0.4916ms)
MOPED: 127.0.0.1:27017 QUERY database=hotel_abadi_development collection=admins selector={"$query"=>{"_id"=>"537f8ad9b4f2d7c124000001"}, "$orderby"=>{:_id=>1}} flags=[:slave_ok] limit=-1 skip=0 batch_size=nil fields=nil (0.7987ms)
MOPED: 127.0.0.1:27017 QUERY database=hotel_abadi_development collection=admins selector={"$query"=>{"_id"=>"537f8ad9b4f2d7c124000001"}, "$orderby"=>{:_id=>1}} flags=[:slave_ok] limit=-1 skip=0 batch_size=nil fields=nil (0.7885ms)
MOPED: 127.0.0.1:27017 QUERY database=hotel_abadi_development collection=facilities selector={"$query"=>{"admin_id"=>"537f8ad9b4f2d7c124000001"}, "$orderby"=>{:_id=>1}} flags=[:slave_ok] limit=-1 skip=0 batch_size=nil fields=nil (0.8206ms)
Completed 500 Internal Server Error in 502.0ms
NoMethodError (undefined method `id' for #<ActiveSupport::HashWithIndifferentAccess:0xa6ae334>):
app/controllers/facilities_controller.rb:21:in `update'
Rendered /home/jesus/.rvm/gems/ruby-2.0.0-p353/gems/actionpack-3.2.15/lib/action_dispatch/middleware/templates/rescues/_trace.erb (2.5ms)
Rendered /home/jesus/.rvm/gems/ruby-2.0.0-p353/gems/actionpack-3.2.15/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (2.4ms)
Rendered /home/jesus/.rvm/gems/ruby-2.0.0-p353/gems/actionpack-3.2.15/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (17.7ms)
In order to solve the problem, I have also tried to use fields_for with the nested attributes but I obtain the same error. The main files which defines the application are the next:
app/models/facilities.rb
class Facilities
...
field :description, type: String
field :language, type: Symbol, default: :es
has_many :characteristics, dependent: :destroy
accepts_nested_attributes_for :characteristics, allow_destroy: true
...
end
app/models/characteristic.rb
class Characteristic
...
field :title, type: String
field :description, type: String
field :language, type: Symbol, default: :es
belongs_to :admin
has_one :upload, dependent: :destroy
accepts_nested_attributes_for :upload, allow_destroy: true
...
end
app/controllers/facilities_controller.rb
class FacilitiesController < ApplicationController
load_and_authorize_resource
respond_to :json, :html
...
def update
#facilities.update_attributes!( params[:facilities] )
respond_with #facilities, api_template: :general, location: hotel_path
end
...
end
app/views/facilities.html.haml
= form_for facilities, url: facilities_path( facilities ) do |f|
= f.text_area :description
.facilities_form
- facilities.characteristics.each_with_index do |char, index|
= form_for characteristic, url: characteristic_path( characteristic ), html: { method: :put } do |d|
= d.hidden_field :id, name: 'facilities[characteristics][][id]'
= d.text_field :title, width: 20, size: 20, name: 'facilities[characteristics][][title]'
= d.text_area :description, width: 20, rows: 4, cols: 22, name: 'facilities[characteristics][][description]'
= f.submit "Send"
Solved:
In the nested attributes, I manually put the name of the fields because I am using another form_for for them. In that names, I use "facilities[characteristics][][name_of_field]", but when we need to use nested attributes, we have to put "characteristics_attributes", so the correct name is "facilities[characteristics_attributes][][name_of_field]".
I've spotted that you use facilities instead of facility both in view and controller.
I assume the problem is load_and_authorize_resource in FacilitiesController try to load #facility extracting id from params. So, change facilities_path( facilities ) to facilities_path(#facility) or something similar.

rails heroku query help PGError: ERROR: operator does not exist: integer ~~ unknown

Im deploying a rails 3.2.8 with ruby 1.9.3 in heroku, locally the query shows all books as results or none, and in heroku it just shows the following error.
Started GET "/books/advanced_search?utf8=%E2%9C%93&title=elinor&author=&isbn=&commit=Search" for 157.253.204.87 at 2012-08-22 15:38:03 +0000
Parameters: {"utf8"=>"✓", "title"=>"elinor", "author"=>"", "isbn"=>"", "commit"=>"Search"}
Processing by BooksController#advanced_search as HTML
Rendered books/advanced_search.html.erb within layouts/application (24.0ms)
Completed 500 Internal Server Error in 25ms
ActionView::Template::Error (PGError: ERROR: operator does not exist: integer ~~ unknown
LINE 1: ...tle LIKE '%elinor%' and author LIKE '%%' and isbn LIKE '%%')
HINT: No operator matches the given name and argument type(s). You might need to add explicit type casts.
Im trying to find books in my mini catalog via title which is an string, author which is a text and isbn which is an integer, by any one of them or by all.
Heres my query:
#books = Book.paginate(
page: params[:page], per_page: 10,
:conditions => ['
title like ? ||
author like ? ||
isbn like ?',
{ :title => "%#{params[:title]}%",
:author => "%#{params[:author]}%",
:isbn => params[:isbn].to_i
}
]
)
Heres the model:
class Book < ActiveRecord::Base
attr_accessible :author, :isbn, :title, :description
has_many :reviews, dependent: :destroy
has_many :ratings, dependent: :destroy
validates :author, presence: true
validates :description, presence: true
validates :isbn, presence: true
validates :title, presence: true
end
Thank you all for your help!
As it turns out the error happened because DBs do not do like queries with integers!

How to validate uniqueness of nested models in the scope of their parent model in Rails 3.2?

Here is an example of my problem.
I have a 'Room' model:
class Room < ActiveRecord::Base
has_many :items, :inverse_of => :room
accepts_nested_attributes_for :items
end
And I have an 'Item' model:
class Item < ActiveRecord::Base
belongs_to :room, :inverse_of => :items
validates :some_attr, :uniqueness => { :scope => :room}
end
I want to validate the uniqueness of the :some_attr attribute of all the Items which belongs to a certain room.
When I try to validate the items, I get this error:
TypeError (Cannot visit Room)
I cannot set the scope of the validation to be :room_id since the items are not saved yet so the id is nil. I also want to prevent using custom validators in the 'Room' model.
Is there any clean way to do it in Rails? I also wonder if I set the :inverse_of option correctly...
I don't see anything wrong with how you're using inverse_of.
As for the problem, in a similar situation I ended up forcing a uniqueness constraint in a migration, like so
add_index :items, [ :room_id, :some_attr ], :unique => true
This is in addition to the AR-level validation
validates_uniqueness_of :some_attr, :scope => :room_id
(I'm not sure if it's valid to use the association name as a scope, won't the DB adapter raise an exception when trying to refer to the non-existent room column in a query?)

passing object for polymorphic lookup parameter in Rails find/where

Let's say I have:
class Comment < ActiveRecord::Base
belongs_to :commentable, :polymorphic => true
end
class Article < ActiveRecord::Base
has_many :comments, :as => :commentable
end
class Photo < ActiveRecord::Base
has_many :comments, :as => :commentable
#...
end
now I want to find all comments on Jim's photo:
#jims_photo = Photo.where(:of => "Jim")
#photo_comments = Comment.where(:commentable => #jims_photo)
this seems to not work in rails (Rails 3). The generated query seems to not expand the polymorphic object into commentable_id and commentable_type fields:
SQLite3::SQLException: no such column: comments.commentable:
I'm new to ruby and rails so I might be using the paradigm incorrectly but my expectation was that rails automatically expands
:commentable => #jims_photo
to:
:commentable_id => #jims_photo.id, :commentable_type => #jims_photo.class.name
If you want to be really safe with:
:commentable_id => #jims_photo.id, :commentable_type => #jims_photo.class.name
Then I'd recommend replacing .class.name with .base_class (you don't actually need the name: to_s returns name and will be called automatically).
The reason for this is that when ActiveRecord saves the _type for a polymorphic association it'll use base_class to ensure it's not saving a class which itself is a polymorphic one.
If you play with store_full_sti_class you'll probably have to take even more precautions.
I highly recommend looking at Rails' STI code, here.
The guides for Rails are one of the best so I'd suggest you start reading about Polymorphic Associations
You class declarations looks OK and I'm assuming that you're migrations is as well. But just for the sake of it. Let's say it looks like this:
class CreateComment < ActiveRecord::Migration
def change
create_table :comments do |t|
t.string :name
t.references :commentable, :polymorphic => true
# this is the equivalent of
# t.integer :commentable_id
# t.string :commentable_type
t.timestamps
end
end
end
Not if you have a Article or Photo object and you want to get the comments for that object then Thilo's suggestion is right on. All you need to do is this: #jims_photo.comments
If, on the other hand, you have a an instance of the Comment model, you can get the parent like this: #comment.commentable. But if you want to get Jim's photo comments best to do it like that. Otherwise, you'd have to supply as arguments both the :commentable_id and commentable_type. I'm not aware of any finder that expands the polymorphic object into commentable_id and commentable_type fields for you.
But you can always create a class method for that:
def self.find_by_parent(parent)
where(:commentable_id => parent.id, :commentable_type => parent.class.name)
end

Mixing has_one and has_and_belongs_to_many associations

I'm trying to build a database of urls(links). I have a Category model that has and belongs to many Links.
Here's the migration I ran:
class CreateLinksCategories < ActiveRecord::Migration
def self.up
create_table :links_categories, :id => false do |t|
t.references :link
t.references :category
end
end
def self.down
drop_table :links_categories
end
end
Here's the Link model:
class Link < ActiveRecord::Base
validates :path, :presence => true, :format => { :with => /^(#{URI::regexp(%w(http
https))})$|^$/ }
validates :name, :presence => true
has_one :category
end
Here's the category model:
class Category < ActiveRecord::Base
has_and_belongs_to_many :links
end
And here's the error the console kicked back when I tried to associate the first link with the first category:
>>link = Link.first
=> #<Link id: 1, path: "http://www.yahoo.com", created_at: "2011-01-10...
>>category = Category.first
=> #<category id : 1, name: "News Site", created_at: "2011-01-11...
>>link.category << category
=> ActiveRecord::StatementInvalid: SQLite3::Exception: no such column :
categories.link_id:
Are my associations wrong or am I missing something in the database? I expected it to find the links_categories table. Any help is appreciated.
Why are you using HABTM here at all? Just put a belongs_to :category on Link, and a has_many :links on Category. Then in the db, you don't need a join table at all, just a :category_id on the links table.
But, if you do want a HABTM here, from a quick glance, the first thing I noticed is that your join table is named incorrectly -- it should be alphabetical, categories_links.
The second thing is that you can't mix has_one and has_and_belongs_to_many. HABTM means just that -- A has many of B and A belongs to many of B; this relationship implies that the opposite must also be true -- B has many of A and B belongs to many of A. If links HABTM cateogries, then categories must HABTM links.
See http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#method-i-has_and_belongs_to_many