How do I achieve this same result using Active Query Methods? - ruby-on-rails-3

This is what I want to achieve using active query method I was asked not to do array iterations but instead use active query methods to achieve this
def index
#measurements = current_user.measurements.with_units.created_on
data = Hash.new { |h, k| h[k] = [] }
#measurements.each do |m|
data[m.unit.title] << m
end
render json: { data: data, status: :ok }
end`
This is the image of the expected JSON i wish to achieve with Active query method
and here are my models for Measurement and Units
class Measurement < ApplicationRecord
belongs_to :user
belongs_to :unit
scope :with_units, -> { includes(:unit) }
scope :created_on, -> { order('created_at DESC') }
validates :value, presence: true
end
Model for Units
class Unit < ApplicationRecord
has_many :measurements
scope :with_measurements, -> { includes(:measurements) }
scope :with_user_id, ->(user) { where(user_id: user.id) }
validates :title, presence: true
end
Schema table for measurements
create_table "measurements", force: :cascade do |t|
t.integer "unit_id"
t.integer "user_id"
t.float "value"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
Schema table for Units
create_table "units", force: :cascade do |t|
t.string "title"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end

Use as_json to convert ActiveRecord collection into json.
def index
#measurements = current_user.measurements.with_units.created_on
render json: { data: #measurements.as_json(include: :unit) , status: :ok }
end

Related

How to get has_and_belongs_to_many relation objects together

I have HABTM associated tables like below.
class User < ActiveRecord::Base
has_and_belongs_to_many :groups
end
class Group < ActiveRecord::Base
has_and_belongs_to_many :users
end
How do I get User(s) with associated Groups together(nested), like below
{
id: 8,
name: "John",
groups: [
{
id: 17,
name: "Alpha Group",
user_id: 8
},
{
id: 18,
name: "Bravo Group",
user_id: 8
}
],
},
Is there a nice rails way of doing this?
I can manually create object like above but it would be nice to have a simpler query.
def index
#group = Group.find(params[:id])
respond_to do |format|
format.html
format.json { #group.users.map do |user|
user.to_json(:include => :groups)
end
}
end
end
It'll return an array like:
[
{
"id":1,
"email":"admin#example.com",
"groups":[
{
"id":1,
"name":"Yo"
},
{
"id":2,
"name":"Bro"
},
]
},
{
"id":2,
"email":"valar#example.com",
"groups":[
{
"id":1,
"name":"Arya"
},
{
"id":2,
"name":"Stark"
},
]
}
]

Autosave issue in rails 3.2

In the given code,
class Supplier < ActiveRecord::Base
has_one :criteria, foreign_key: "crt_sup_id", :autosave => true
self.primary_key = 'sup_id'
end
class Criteria < ActiveRecord::Base
belongs_to :supplier, foreign_key: "crt_sup_id"
self.primary_key = 'crt_id'
self.table_name = 'criterias'
end
autosave is not working when I am submitting the form. Supplier records are created but not Criteria.
Form code
class SupplierForm < Netzke::Basepack::Form
def configure(c)
c.model = 'Supplier'
super
c.items = [
{field_label: "Name", name: :bname},
{field_label: "Detail", name: :detail},
{
layout: :hbox, border: false, defaults: {border: false}, items: [
{
flex: 1,
layout: :anchor,
defaults: {anchor: "-8"},
items: [
{field_label: "Value 1", name: :criteria__val_one, xtype: :checkbox, nested_attribute: true},
{field_label: "Value 2", name: :criteria__val_two, xtype: :checkbox, nested_attribute: true}
]
}
]
}
]
end
end
Controller code
def index
end
Solved with the help of Netzke author. Replace criteria__val_one with criteria_val_one and
criteria__val_two with criteria_val_two. Create virtual attributes in the model class. Now all the values entered in the form is accessible with these virtual attributes and can be saved. Credit goes to Max Gorin. Thanks for the great work (Netzke)

Rails error with rspec: "expected valid? to return true, got false"

I'm new to rails, and after completing Michael Hartl's Ruby on Rails Tutorial, I am trying to expand some of the functionality. I started by changing the microposts so that they collect more data.
When running a rspec test, I can't figure out why I am getting this error:
$ bundle exec rspec spec/models/micropost_spec.rb
...............F.....
Failures:
1) Micropost
Failure/Error: it { should be_valid }
expected valid? to return true, got false
# ./spec/models/micropost_spec.rb:46:in `block (2 levels) in <top (required)>'
Finished in 1.57 seconds
21 examples, 1 failure
Failed examples:
rspec ./spec/models/micropost_spec.rb:46 # Micropost
micropost_spec.rb
require 'spec_helper'
describe Micropost do
let(:user) { FactoryGirl.create(:user) }
before { #micropost = user.microposts.build(content: "Lorem ipsum",
title: "This is a test title",
privacy: "1",
groups: "This is a test Group",
loc1T: "21 Bond St. Toronto, Ontario",
loc1Lat: "43.654653",
loc1Lon: "-79.377627",
loc2T: "21 Bond St. Toronto, Ontario",
loc2Lat: "43.654653",
loc2Lon: "-79.377627",
startTime: "Jan 1, 2000 12:01:01",
endTime: "Jan 2, 2000 12:01:01",
imageURL: "http://i.cdn.turner.com/cnn/.e/img/3.0/global/header/hdr-main.gif")
puts #micropost.errors.messages
}
#before { #micropost = user.microposts.build(title: "This is a test title") }
#before { #micropost = user.microposts.build(privacy: "1") }
#before { #micropost = user.microposts.build(groups: "This is a test Group") }
#before { #micropost = user.microposts.build(loc1T: "21 Bond St. Toronto, Ontario") }
#before { #micropost = user.microposts.build(loc1Lat: "43.654653") }
#before { #micropost = user.microposts.build(loc1Lon: "-79.377627") }
#before { #micropost = user.microposts.build(loc2T: "21 Bond St. Toronto, Ontario") }
#before { #micropost = user.microposts.build(loc2Lat: "43.654653") }
#before { #micropost = user.microposts.build(loc2Lon: "-79.377627") }
#before { #micropost = user.microposts.build(startTime: "Jan 1, 2000 12:01:01") }
#before { #micropost = user.microposts.build(endTime: "Jan 2, 2000 12:01:01") }
#before { #micropost = user.microposts.build(imageURL: "http://i.cdn.turner.com/cnn/.e/img/3.0/global/header/hdr-main.gif") }
subject { #micropost }
it { should respond_to(:content) }
it { should respond_to(:user_id) }
it { should respond_to(:user) }
it { should respond_to(:title) }
it { should respond_to(:privacy) }
it { should respond_to(:groups) }
it { should respond_to(:loc1T) }
it { should respond_to(:loc1Lat) }
it { should respond_to(:loc1Lon) }
it { should respond_to(:loc2T) }
it { should respond_to(:loc2Lat) }
it { should respond_to(:loc2Lon) }
it { should respond_to(:startTime) }
it { should respond_to(:endTime) }
it { should respond_to(:imageURL) }
its(:user) { should == user }
it { should be_valid }
describe "accessible attributes" do
it "should not allow access to user_id" do
expect do
Micropost.new(user_id: user.id)
end.to raise_error(ActiveModel::MassAssignmentSecurity::Error)
end
end
describe "when user_id is not present" do
before { #micropost.user_id = nil }
it { should_not be_valid }
end
describe "with blank content" do
before { #micropost.content = " " }
it { should_not be_valid }
end
describe "with content that is too long" do
before { #micropost.content = "a" * 141 }
it { should_not be_valid }
end
end
micropost.rb
class Micropost < ActiveRecord::Base
attr_accessible :content, :title,:privacy,:groups,:loc1T,:loc1Lat,:loc1Lon,:loc2T,:loc2Lat,:loc2Lon,:startTime,:endTime,:imageURL
belongs_to :user
validates :user_id, presence: true
validates :title, presence: true
validates :privacy, presence: true
validates :groups, presence: true
validates :loc1T, presence: true
validates :loc1Lat, presence: true
validates :loc1Lon, presence: true
validates :loc2T, presence: true
validates :loc2Lat, presence: true
validates :loc2Lon, presence: true
validates :startTime, presence: true
validates :endTime, presence: true
validates :imageURL, presence: true
validates :content, presence: true, length: { maximum: 140 }
default_scope order: 'microposts.created_at DESC'
def self.from_users_followed_by(user)
followed_user_ids = "SELECT followed_id FROM relationships
WHERE follower_id = :user_id"
where("user_id IN (#{followed_user_ids}) OR user_id = :user_id",
user_id: user.id)
end
end
factories.rb
FactoryGirl.define do
factory :user do
#name "Michael Hartl"
#email "michael#example.com"
sequence(:name) { |n| "Person #{n}" }
sequence(:email) { |n| "person_#{n}#example.com"}
password "foobar"
password_confirmation "foobar"
factory :admin do
admin true
end
end
factory :micropost do
content "Lorem ipsum"
title "This is a test title"
privacy "1"
groups "This is a test Group"
loc1T "21 Bond St. Toronto, Ontario"
loc1Lat "43.654653"
loc1Lon "-79.377627"
loc2T "21 Bond St. Toronto, Ontario"
loc2Lat "43.654653"
loc2Lon "-79.377627"
startTime "Jan 1, 2000 12:01:01"
endTime "Jan 2, 2000 12:01:01"
imageURL "http://i.cdn.turner.com/cnn/.e/img/3.0/global/header/hdr-main.gif"
user
end
end
I'm not sure if there is anything else you need me to post.
It is not valid because your model object is not passing your validations. In your before block, after you create #micropost, add this line to see which validations are failing
puts #micropost.errors.messages
There will be a hash of validations (fields and error messages) that have failed. Fix those and then your object will be valid. Some earlier commenters had suggestions on where to start to help fix the problem.
This got rid of the errors.
micropost_spec.rb
describe Micropost do
let(:user) { FactoryGirl.create(:user) }
before { #micropost = user.microposts.build(content: "Lorem ipsum",
title: "This is a test title",
privacy: "1",
groups: "This is a test Group",
loc1T: "21 Bond St. Toronto, Ontario",
loc1Lat: "43.654653",
loc1Lon: "-79.377627",
loc2T: "21 Bond St. Toronto, Ontario",
loc2Lat: "43.654653",
loc2Lon: "-79.377627",
startTime: "Jan 1, 2000 12:01:01",
endTime: "Jan 2, 2000 12:01:01",
imageURL: "http://i.cdn.turner.com/cnn/.e/img/3.0/global/header/hdr-main.gif")
puts #micropost.errors.messages
}

Mongoid querying

I have some application on RoR with Mongodb database. I use Mongoid mapper. Model post.rb
class Post
include Mongoid::Document
field :title, :type => String
field :text, :type => String
embeds_many :comments
end
Model comment.rb
class Comment
include Mongoid::Document
field :name, :type => String
field :content, :type => String
embedded_in :post, :inverse_of => :comments
end
In database this post with some comment has next structure:
{
"_id": ObjectId("4ecbeacf65430f0cef000003"),
"comments": {
"0": {
"name": "my name",
"content": "example content",
"_id": ObjectId("4ecbead365430f0cef000005")
},
"1": {
"name": "some name",
"content": "example content",
"_id": ObjectId("4ecbead665430f0cef000007")
},
"2": {
"name": "some name",
"content": "example content",
"_id": ObjectId("4ecbeada65430f0cef000009")
}
},
"text": "example text",
"title": "example title"
}
And, for example, in database was a few posts with my comments.
I need to find all posts, where "name": "my name", i.e. I need to find all editable by me posts.
It should appear as a array of comments instead of a hash. See my example below.
Also, as per the mongoid docs use the new style field declarations.
comment.rb:
class Comment
include Mongoid::Document
field :name, type: String
field :content, type: String
embedded_in :post
end
post.rb:
class Post
include Mongoid::Document
field :title, type: String
field :text, type: String
embeds_many :comments
end
Rails Console:
p = Post.new(:title => "title", :text => "post")
c1 = Comment.new(:name => "Tyler", :comment => "Awesome Comment!")
c2 = Comment.new(:name => "Joe", :comment => "comment 2")
p.comments << c1
p.comments << c2
p.save
Mongo Console:
> db.posts.findOne()
{
"_id" : ObjectId("4ecd151d096f762149000001"),
"title" : "title",
"text" : "post body",
"comments" : [
{
"name" : "Tyler",
"comment" : "Awesome Comment!",
"_id" : ObjectId("4ecd1569096f762149000002")
},
{
"name" : "Joe",
"comment" : "comment 2",
"_id" : ObjectId("4ecd157f096f762149000003")
}
]}
Then, to do the query you want, which I think was "comments posted by me?":
> db.posts.findOne({"comments.name": "Tyler"})
Also, I would add an index to the comments.name field:
> db.posts.ensureIndex({"comments.name": 1})

polymorphic rails association fails on inherited class?

I'm having trouble doing the reverse polymorphic association when I have an inherited class. Anyone know what's going on?
ruby-1.9.2-rc2 > Label.first
=> #<Label id: 1, owner_id: 1, owner_type: "Student", name: "Lorem", created_at: "2011-01-23 05:02:29", updated_at: "2011-01-23 05:02:29">
ruby-1.9.2-rc2 > Label.first.owner
=> #<Student id: 1, email: "alice1#example.com", ..., avatar_updated_at: nil>
ruby-1.9.2-rc2 > Label.first.owner.labels
=> []
class Student < User
has_many :labels, :as => :owner
class Label < ActiveRecord::Base
belongs_to :owner, :polymorphic => true
Note: just for good measure (not that this should be any different, but just in case...)
User.find(1).labels
=> []
Also
l = Label.find(4)
=> #<Label id: 4, owner_id: 2, owner_type: "Student", name: "sit", created_at: "2011-01-23 05:02:29", updated_at: "2011-01-23 05:02:29">
ruby-1.9.2-rc2 > l.owner_type = "User"
=> "User"
ruby-1.9.2-rc2 > l.save
=> true
ruby-1.9.2-rc2 > Student.find(2).labels
=> [#<Label id: 4, owner_id: 2, owner_type: "User", name: "sit", created_at: "2011-01-23 05:02:29", updated_at: "2011-01-23 07:13:37">]
Still not sure why it was failing (well, I can guess, given the Student/User dichotomy), but for future reference this hack works:
has_many :labels, :conditions => ["owner_type = ?", "Student"],
:foreign_key => "owner_id"