CollectionProxy object in rails 4? - activerecord

I am using rails 4 and making an application in which Question_sets has many Questions and Questions has many answers. Now what i want is to update one attribute of question model and one attribute of answer model through questions sets.
#question_set.questions.inspect
It gives the output
OUTPUT:
ActiveRecord::Associations::CollectionProxy
[Question id: nil, title: "werewr", question_type: "Slider", description: "ewrewrew", is_shown_in_report: false, question_set_id: nil, user_id: nil, created_at: nil, updated_at: nil]
But when i am accessing any of the attribute or trying to update it, it will give an error that is undefined "attribute_name".
can any tell how to access the attributes of the this collectionproxy object.

questions is returning a collection (like an Array) of Question objects. So you need to itterate over the collection:
#question_set.questions.each do |question|
question.title
end

Related

Ruby query need to update

Relationship:
account has_many users
user has_one sima
primary_partner_id is "account_id" which is passing as params.
User.where(primary_partner_id: 2).map{|a| a.sima}.reject{ |e| e.to_s.empty?}
Results as below:
[
#<Sima id: 93, user_id: 7, interviewer_account_user_id: 1945, interviewer_completion_date: "2017-06-09", transcriber_account_user_id: nil, transcriber_completion_date: nil, biographer_account_user_id: nil, biographer_completion_date: nil, reviewer_account_user_id: nil, reviewer_completion_date: nil, status: "accepted", autobiographical_form: "27381", autobiographical_form_completion_date: nil, sima_level_id: "1", created_at: "2017-06-06 20:17:57", updated_at: "2017-06-09 10:04:33", autobiographical_form_comments: nil, on_hold: nil, comments: [{:comment=>"easylims.xlsx", :user_name=>"Mike Burns", :created_at=>2017-06-06 20:17:57 UTC}, {:comment=>"ok", :user_name=>"SIMA Admin", :created_at=>2017-06-06 20:19:33 UTC}], interviewer_id: nil, interviewer_start_date: nil, transcriber_start_date: nil, biographer_start_date: nil, reviewer_start_date: nil>,
#<Sima id: 92, user_id: 1, interviewer_account_user_id: nil, interviewer_completion_date: nil, transcriber_account_user_id: nil, transcriber_completion_date: nil, biographer_account_user_id: nil, biographer_completion_date: nil, reviewer_account_user_id: nil, reviewer_completion_date: nil, status: "accepted", autobiographical_form: "27437", autobiographical_form_completion_date: nil, sima_level_id: "1", created_at: "2017-06-06 20:01:50", updated_at: "2017-06-06 20:22:50", autobiographical_form_comments: nil, on_hold: nil, comments: [{:comment=>"original_msg (1).txt", :user_name=>"bild_cloud#bild.org", :created_at=>2017-06-06 20:01:50 UTC}, {:comment=>"ok", :user_name=>"SIMA Admin", :created_at=>2017-06-06 20:22:05 UTC}], interviewer_id: nil, interviewer_start_date: nil, transcriber_start_date: nil, biographer_start_date: nil, reviewer_start_date: nil>
]
Sima has field like status and I have three statuses as "pending, accepted, declined"
Question:
Now I want to show the result as per status which will pass by the user as params. So the result should be as per status from Sima. If params is status=" accepted" then Sima list will have only which has status "accepted"
By doing this you can avoid N+1 Query problem
User.includes(:sima).where(sima: {status: params[:status]},primary_partner_id: params[:account_id]).map(&:sima)
If you are using joins --> In map statement each time query will be called so that we are preferred to use includes, for more Information
you can refer this link
http://guides.rubyonrails.org/active_record_querying.html
You could join the simas model and the user model
User.joins("JOIN simas ON simas.user_id = users.id")
.where(primary_partner_id: 2, "simas.status": 'accepted')
.map{|a| a.sima}
As I am understanding your above all statements. End user us passing account id and you want to take sima status from the end user as well.
You can file all users id from account first. then find sima which will belong to that user and here you can pass sima status as well.
#aBadAssCowboy given the correct answer which is first one only. But from that query, you will get all Sima either nil or with value.
user_ids = User.where(primary_partner_id: params[:account_id]).pluck(:id)
Sima.where(user_id: user_ids, status: params[:status]).reject{ |e| e.to_s.empty?}
Hope this will help you.
User.preload(:sima).joins(:sima).where(sima: {status: params[:status]}, primary_partner_id: params[:account_id]).map(&:sima)
or
As account to users relationship is already defined you can directly do...
Account.find(2).users.preload(:sima).joins(:sima).where(sima: {status: params[:status]}).map(&:sima)
With the same associations you have on the models, you could do (assuming that user passes status they wants to see:
user_ids = User.where(primary_partner_id: 2).pluck(:id)
Sima.where(user_id: user_ids, status: params[:status])
The above will hit the database twice but that's totally fine. You could use includes and map but I don't think that will be a huge performance benefit depending on the number of users on a account you have. Eitherways, here it is:
User.includes(:sima)
.references(:sima) # you need this if you use Rails 4 +
.where(users: { primary_partner_id: 2 })
.where(simas: { status: params[:status] })
.map(&:sima)
However, I suggest you update Account model with has_many through associations.
class Account
has_many :users
has_many :simas, through: :users
end
# To get sima of a particular status
Account.find(2).simas.where(status: param[:status])
This way, you can just do account.simas to get simas from all the users that belong to that account.
If you add to Sima Model
belongs_to :user You can get an list of Sima by
Sima.joins(:users).where(users: { primary_partner_id: 2 }).where(status: 'accepted')

Update a value into a JSON string with Ruby ActiveRecord?

Sorry to ask this question but I'm really newbie with Ruby and I need help to update several records on mu database.
Starting with the code below. Could you help me to write a console query or instruction that help me to change the value of the "size"=>"001" to "size"=>"400".
2.1.2 :050 > orders.first
=> #<Order id: 3193, qty: 3193, data: {"size"=>"001", "barcode"=>"123456789", "barcode_type"=>"128"}, order_item_id: 473, sub_item_id: 001, created_at: "2015-07-26 05:03:32", updated_at: "2015-07-26 05:03:32">
Then what should I do if I want to update all orders, not only the first one?
Loops through each order
Eg:
orders = Order.all
orders.each do |order|
order.data[:size] = "400"
order.save
end
Also, "serialize :data" in your Order model if not added
After testing the solution of M Kumar I found the correct way to do it is
orders = Order.all
orders.each do |order|
order.data["size"] = "400"
order.save
end

Mongoid push with upsert

I've got model User:
class User
field :username, type: String
embeds_many :products
end
class Product
field :name, type: String
embedded_in :user
end
I would like to have single operation that would:
insert the user
update the user in case the user exists already (this i can easily do with upsert)
push the products
This works for upserting:
User.new(username: 'Hello').upsert
The problem is that this will delete the embedded products (the products attribute is not specified).
Can I ask mongoid to skip setting array to empty?
Can I ask mongoid to push new products at the end of products array?
Something like this:
User.new(username: 'Hello').push(products: [Product.new(name: 'Screen')]).upsert
Finally I ended up by manually writing the following query:
User.mongo_client[:users].update_one({username: 'Hello'},
{"$set" => {first_name: 'Jim', last_name: 'Jones'},
"$pushAll" => [products: [{name: 'Screen'}, {name: 'Keyboard'}]
},
upsert: true)
Where:
$set - are the params that we want to set for a given document
$pushAll - when you use $push you can specify only one element, $pushAll allows you to append multiple elements (when you specify only one it will behave like $push)
upsert - will do the insert/update magic in the mongodb
In the second hash you can also specify $inc, $dec, $pop, $set etc... which is quite useful.

Sinatra activerecord initialize

I got a strange situation.Could somebody give me advise ?
I am developing an App with
Ruby1.8.7
Sinatra 1.4.4
Activerecord 3.2.14
Mysql 5.6.19
I almost finish developing but at the last moment I got stack.
I have two tables in MySQL.
CREATE TABLE items(
id INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
type text,
keyword text,
postid INT,
created_at datetime NOT NULL);
CREATE TABLE comments(
id INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
comment text,
yourname INT,
postid INT,
created_at datetime NOT
NULL);
In Sinatra app , I declared class.
class Comment < ActiveRecord::Base end
class Item < ActiveRecord::Base end
For debugging purpose , I wrote this code and run.
get "/l" do
# New comment and set initial value.
y={:yourname =>"3",:comment =>"commenttest"}
com = Comment.new(y)
p com.attribute_names()
p com
# New items and set initial value.
kensaku = {:type=>"000"}
k = Item.new(kensaku)
p k.attribute_names()
p k
k.type="555"
p k
end
So now I found very interesting things on console.
Comment class succeeded to new with initial value.
But Item class succeeded to new but it is not set initial value.
I wonder why it happens ?
#-- Comment class
["postid", "id", "comment", "created_at", "yourname"]
#<Comment id: nil, comment: "commenttest", yourname: 3, postid: nil, created_at: nil>
#-- Item class
["type", "postid", "id", "keyword", "created_at"]
#<Item id: nil, type: nil, keyword: nil, postid: nil, created_at: nil>
#<Item id: nil, type: "555", keyword: nil, postid: nil, created_at: nil>
The column name type is a reserved word in ActiveRecord:
While these column names are optional, they are in fact reserved by
Active Record. Steer clear of reserved keywords unless you want the
extra functionality. For example, type is a reserved keyword used to
designate a table using Single Table Inheritance (STI). If you are not
using STI, try an analogous keyword like "context", that may still
accurately describe the data you are modeling.

undefined method `[]' for nil:NilClass When Looping Through Ruby Array

I have a hash of values that I am trying to loop through to display the values in my view.
The hash is set up as:
{:position=>#<Position id: 2, user_id: 1, title: "Something", city: "Denver", state: "CO",
created_at: "2012-07-06 02:55:42", updated_at: "2012-07-06 02:55:42">, :experience=>[#
<Experience id: 4, user_id: 1, position_id: 2, description: "Did some stuff", created_at:
"2012-07-02 06:24:33", updated_at: "2012-07-02 06:24:33">, #<Experience id: 6, user_id: 1,
position_id: 2, description: "Did other stuff", created_at: "2012-07-02 06:24:33",
updated_at: "2012-07-02 06:24:33">]}
It is created by taking ActiveRecord results and inserting them into a hash (if you want more details, I am happy to add them).
In my view, I attempt to loop through the hash:
<% for i in 0..#positions.length %>
<%= #positions[i][:position][:title] %>
<%= #positions[i][:position][:city] %>
<% end %>
When I open it in the browser, I get an error undefined method '[]' for nil:NilClass. If I only use #positions[i], it will dump out the raw hash (first one, then second, and so on). It's when I add [:position], it doesn't work. I can access the values in the console using #positions[0][:position][:title]. When I tried writing the loop in console, I got the same error.
I know that i is counting because I can have it display the value in the browser and it is working correctly.
I have tried using #positions.each do |job| but ran into the same error. I tried adding another indices in other places: #positions[i][:position][0].
Basically, I have two models: Position and Experience. Experience is a child to Position. I want to get Experience for a given Position but only certain experience like ones that occur within a certain time frame. There is most likely a better approach to this and I just don't know it so I'm open to suggestions.
Thanks.
It seems you have an object of Postion class assigned to the key :position. So you access title and city through accessor methods and not with [].
<% #positions.each do |job| %>
<%= job[:position].title %>
<%= job[:position].city %>
<% end %>

Resources