undefined method `assign_attributes' for [13]:Array - ruby-on-rails

My app is set up that when product.sold attribute is 1 means an item is sold and it wont show up in the store views. I am trying to get it so when the customer checks out the product.sold attribute is updated when the item is purchased.
Here is the line of code in my controller that should be updating the product.sold attribute from nil to 1:
class ChargesController < ApplicationController
def create
#order.order_items.map{ |o| o.product.id }.assign_attributes(sold: 1)
end
here are my associations:
OrderItem belongs_to :product
OrderItem belongs_to :order
Product has_many :order_items
Order has_many :order_items
here is the error I am getting when I try to purchase a product with an id of 13
NoMethodError in ChargesController#create
undefined method `assign_attributes' for [13]:Array
Extracted source (around line #12):
#OrderMailer.order_email(#order).deliver_now
#order.update_attribute(:order_status_id, 2)
#order.order_items.map{ |o| o.product.id }.assign_attributes(sold: 1)
#final_amount = #amount
I have also tried update_attributes and update in place of assign_attributes. Not sure what else to try. Let me know if more info is needed.

You are trying to call assign_attributes on array of products IDs, but not models. Try this:
def create
product_ids = #order.order_items.map{ |o| o.product.id }
Product.where(id: product_ids).update_all(sold: 1)
end

Related

How to get parent from child in nested model rails 6

I have issue when try to get parent model from child as below:
Post model
class Post < ApplicationRecord
has_many :post_votes, dependent: :destroy
accepts_nested_attributes_for :post_votes
end
PostVote model
class PostVote < ApplicationRecord
belongs_to :post, optional: true
end
Get parent funtion
def find_owner_post_vote_for_user(user)
#owner_post = Post.first
#owner_post_vote = PostVote.first
if user.id.present?
#owner_post_vote = PostVote.where(user_id: user.id)
#owner_post = #owner_post_vote.post
end
return #owner_post
end
Error log:
ActionView::Template::Error (undefined method `post' for #<PostVote::ActiveRecord_Relation:0x00007fffc23f9c78>):
Get child model #post.post_votes is OK, but get parent model is false.
Any can help me fix this problem? Thank so much!
PostVote.where(user_id: user.id) will return a collection of records. So, on the very next line when you do #owner_post_vote.post It's trying to find a post for a collection of records ActiveRecord_Relation.
if you want to use where, then you should iterate through the collection. Or, you can you find to get a single record. Then you can do #owner_post_vote.post.
Option 1:
if user.id.present?
#owner_post_vote = PostVote.find(user_id: user.id)
#owner_post = #owner_post_vote.post
end
Option 2:
if user.id.present?
#owner_post_vote = PostVote.where(user_id: user.id).first
#owner_post = #owner_post_vote.post
end
Option 3:
if user.id.present?
#owner_post_votes = PostVote.where(user_id: user.id)
#owner_post_votes.each do |post_vote|
# post_vote.post is accessible here
end
end

Can't access prop in has_one relationship

I have two models:
class Post < ApplicationRecord
has_one :metric, dependent: :destroy
end
class Metric < ApplicationRecord
belongs_to :post
end
And for some reason that I don't fully understand, I can't create a new metric through a post:
> post = Post.first 1
> post.metric # => Nil
> post.metric.create # NoMethodError (undefined method `create' for nil:NilClass)
Do I have to declare anything else any of my models to make this work?
You can't call create method on nil class.
Active Record Associations DOC
post = Post.first 1
post.build_metric # will be automatically assigned post_id to metrics but not saved
post.save
#or
post.create_metric # will be automatically assigned post_id to metrics and saved
Alternate solution:
Metric.create(post_id: post.id)
What you're doing is
post = Post.first 1
# You don't tell us what this evaluates to, but I'm assuming a post as the #metric call works
post.metric # => Nil
# You have nil
post.metric.create
# Now you're calling the create method on nil.
What you need to do is
Metric.create(post_id: Post.first.id, etc_attribute: etc_value, ...)
EDIT: Also what 7urkm3n said in his comment-- build_metric and create_metric are cleaner solutions that utilize Rails magic.

Filter nested model attributes in RoR

I have two models: Users and PaymentMethods, the association between this models is:
class User < ApplicationRecord
has_many :payment_methods, dependent: :destroy
end
class PaymentMethod < ApplicationRecord
belongs_to :user, optional: true
end
I want to loop in each user and see in an attribute of PaymentMethod, named 'period_end_date'. so I do this:
#users = User.all
#users.each do |u|
u.payment_methods.last.period_end_date
end
I'm getting this error => NoMethodError: undefined method `payment_methods' for User::ActiveRecord_Relation
The error is shown because I have 2 test users, in the first user there is still no data in the attribute 'period_end_date' and association exist, but is empty, in the second user there is data in the attributes, if I say, u.payment_methods.last.period_end_date I get => Wed, 13 Jun 2018 (only in the second user)
I want to filter in my loop only the users who has data in PaymentMethod attributes for get rid of => NoMethodError: undefined method `payment_methods' for User::ActiveRecord_Relation
How I do this?
thanks
I want to filter in my loop only the users who has data in PaymentMethod attributes for get rid of => NoMethodError: undefined method `payment_methods' for User::ActiveRecord_Relation
The actual problem seems to be you have users without payment methods (see my comment on your question).
You have some options, depending on how you're going to use the results.
1) You can filter out users without payment methods when you query them from the database like this:
#users = User.joins :payment_methods
2) If #users must include users that without payment methods, you can skip them when looping like this:
#users.map do |user|
next unless user.payment_methods.any?
user.payment_methods.last.period_end_date
end
3) You can guard by checking for payment_methods before calling .last.
User.all.map do |user|
user.payment_methods.last.period_end_date if user.payment_methods.any?
end
4) You can add a period_end_date method to the user
class User < ApplicationRecord
def period_end_date
payment_methods.limit(1).pluck :period_end_date
end
end
5) push #4 into the association by extending it with a helper method
class User < ApplicationRecord
has_many :payment_methods, class_name: 'PaymentMethod' do
def last_period_end_date
last.period_end_date if any?
end
end
end
which you can call like this
User.all.map do |user|
user.payment_methods.last_period_end_date
end
If you're really only concerned about PaymentMethods without a period_end_date then try this:
6) You can still filter users when you query them from the database
#users = User.joins(:payment_methods).where.not(payment_methods: { period_end_date: nil })
7) This can be simplified a bit by pushing the where.not conditions into a scope of the PaymentMethod class:
class PaymentMethod < ApplicationRecord
scope :period_ends, -> { where.not period_end_date: nil }
end
and merging it
#users = User.joins(:payment_methods).merge PaymentMethod.period_ends
Notes
payment_methods.last doesn't specify an order, you should set one (either as part of this chain, when you specify the association, or with a default scope) otherwise the order is up to your database and may be indeterminate.
chain .includes(:payment_methods) to eager load the payment methods and avoid n+1 queries
it sounds like a nil period_end_date could be invalid data. Consider adding a validation / database constraint to prevent this from happening

Is possible to append a key value to an ActiveRecord object

I want to have an object that has an associated value added to it.
This is what I am attempting to do:
#users = #search.results
#user_results = []
#users.each do |user|
#user_results = #user_results.push user << {photo_url: UsersPhoto.find_by_user_id(user.id).image_name}
end
I'm getting:
NoMethodError (undefined method `<<' for #):
Is there a way to do something like this?
This is what associations are for. You should just add an association to your User for the UsersPhoto you're trying to find, and use #user.users_photo.image_name.
class User < ActiveRecord::Base
has_one :users_photo
end
Failing that, add a photo_url method to your User model, which wraps up the UsersPhoto.find...:
class User < ActiveRecord::Base
def photo_url
UsersPhoto.find_by_user_id(id).image_name
end
end
Failing that, you can do what you're trying to do, but you'll need to add a attr_accessor :photo_url to your User model, and your syntax is all wrong:
class User < ActiveRecord::Base
attr_accessor :photo_url
end
#users.each do |user|
user.photo_url = UsersPhoto.find_by_user_id(user.id).image_name
end
Why don't you use the .pluck method?
#users = #search.results
#user_results = UsersPhoto.where(user_id: #users.pluck(:id) ).select(:image_name)
To explain, at least from what I am understanding, you want an array of image_names for the results #users. So just get their ids, find those UsersPhotos that match those ids and just get the image_name column

Ruby On Rails Model has no methods

I have a model with a belongs to relationship.
class Product < ActiveRecord::Base
attr_accessible :name, :price, :request_id, :url
# Relationships
belongs_to :request
end
class Request < ActiveRecord::Base
attr_accessible :category, :keyword
# Relationships
has_many :products
end
This is the code in my controller function
product = Product.where({ :asin => asin }).first
# See if the product exists
begin
#This throws a method not found error for where
product = Product.where({ :name => name }).first
rescue
Product.new
# This throws a method not found error for request_id
product.request_id = request.id
product.save
end
I'm trying to create a new product object like so
product = Product.first(:conditions => { :name => name })
When I call that I get an error saying undefined method 'first' for Product:Class
I tried doing Product.new and I can't access any attributes. I get this for every one undefined method 'request_id=' for #<Product:0x007ffce89aa7f8>
I've been able to save request objects. What am I doing wrong with products?
EDIT:
So as it turns out there was an old Product data type that was being imported that wasn't an ActiveRecord class. It was using that instead of my Product::ActiveRecord. I deleted that import and it's good to go. Sorry to have wasted everybody's time.
Not sure what the proper protocol is here for what to do with this question.
Is your Product class an ActiveRecord::Base class? You can find out by running:
Product.ancestors.include?(ActiveRecord::Base)
If this returns false, it's getting the class loaded from somewhere else.
First check to see that your Product class is set up correctly by typing in:
rails c
# after console has loaded
Product
If this looks correct then we will try to instantiate a product by calling:
# Create a new product
product = Product.new(name: "first product", price: 100, url: "http://www.example.com")
# Persist this object to the database
product.save
If you are missing any attributes run another migration to add them to the Product table.
If none of those suggestions work, check to make sure that there isn't an existing class with the same name in your project. This would cause all kinds of errors and would explain certain methods not being found.

Resources