Rails Accessing data in XML - Undefined Method - ruby-on-rails

I am trying to download products from a Magento store into my Rails database using the "magento-rb" library located here: https://github.com/joelvh/magento-rb
I've tried the following code:
xml_api = Magento::XmlApi.new "http://website.com/api/xmlrpc/", "myusername", "mypassword", :debug => true
products = xml_api.call("catalog_product.list")
products.each do |p|
#exists = Product.where("sku = ?",p["sku"])
if #exists
#product = Product.find_by_sku(p["sku"])
else
#product = Product.new
end
#product.sku = p["sku"]
#product.name = p["name"]
#product.mage_product_id = p["product_id"]
#product.save
end
Unfortunately I am getting this error:
NoMethodError in Admin::ProductsController#test
undefined method `sku=' for nil:NilClass
I should note that I have confirmed that "sku" is indeed an attribute to the Product model, and I have also tried resetting the server. Any ideas?

The way you wrote the code, #exists is always true so even when the sku doesn't exist, the where() method will return an empty array which evaluates to true in ruby.
The only values that evaluate to false in ruby are false and nil.
That's why when you use Product.find_by_sku, it returns nil because the sku doesn't exist and THAT is why you're getting the error undefined method sku= for nil:NilClass.
It's like you're writing nil.sku = p['sku'] which won't work.
To check the existence of a record in the database, it's better to use the 'exists?' method:
if Product.exists?(["sku = ?",p["sku"]])
# product exists
else
# product doesn't exist
end
You can actually skip the extra record checking and only use the find_by_sku method to both check for existence and get the record if it exists at the same time. The following code does the same thing, but it's more "ruby-like":
#product = Product.find_by_sku(p['sku'])
#product = Product.new unless #product
#product.sku = p['sku'] # this is unnecessary
#product.name = p['name']
#product.mage_product_id = p['product_id']
#product.save

Related

Undefined new_record? Ruby Rails

I am trying to check if the domain host url record exist in the domain table before creating it again, but I am getting this error:
undefined method `new_record?' for #<Domain::ActiveRecord_Relation:0x007f320ed8af80>
The class GetMeta is a service object that is getting initialize when a user enter a URL in a form and click submit. I am taking the URL from the form and calling MetaInspector with it to get more meta informations.
The first part (if) new_record method is working perfectly fine, but is creating duplicate values in the domain table. I tried to create a conditional logic, but I am having this bug that I don't know how to fixed.
class GetMeta
include ActiveModel::Model
def initialize(url)
#url = url
end
def new_record
page = MetaInspector.new(#url)
#domain = Domain.where(:host => page.host)
if new_record?
Domain.create! do |url|
url.root_url = page.root_url
url.scheme = page.scheme
url.host = page.host
url.links.build(url: page.url, title: page.best_title, description: page.description)
end
else
Link.create! do |link|
link.url = page.url
link.title = page.best_title
link.description = page.description
end
end
end
private
def new_record?
#domain.new_record?
end
end
The problem is described by an error. Let's see:
undefined method `new_record?' for
#<Domain::ActiveRecord_Relation:0x007f320ed8af80>
The problem is the line
#domain = Domain.where(:host => page.host)
This returns an ActiveRecord relation instead of single record.
You should take a .first or .last.
#domain = Domain.where(:host => page.host).last
That's the fix, but let's see how can we improve the code.
We can use method exists? which is defined in ActiveRecord Relation (docs: http://api.rubyonrails.org/classes/ActiveRecord/FinderMethods.html#method-i-exists-3F)
if Domain.exists?(host: page.host)
Link.create! do |link|
link.url = page.url
link.title = page.best_title
link.description = page.description
end
else
Domain.create! do |url|
url.root_url = page.root_url
url.scheme = page.scheme
url.host = page.host
url.links.build(url: page.url, title: page.best_title, description: page.description)
end
end
This way we don't need instance variable #domain and helper method new_record?
You are calling an instance method from within an instance method. So you need to specify which instance you are referring to. You need to use 'self'. So instead of just calling 'new_record?', try calling self.new_record?

undefined method `+' for nil:NilClass spree

I am running a spree app.
I am getting below error when I try to add any product in the cart.
undefined method `+' for nil:NilClass
This error comes only when I add option types and variants of the same product.
I am not sure what's exactly going wrong here, because I am not doing any changes in the code or something.
This is the extracted source it shows.
if quantity.between?(1, 2_147_483_647)
begin
order.contents.add(variant, quantity, options)
rescue ActiveRecord::RecordInvalid => e
error = e.record.errors.full_messages.join(", ")
end
Here's my order controller's populate function.
# Adds a new item to the order (creating a new order if none already exists)
def populate
order = current_order(create_order_if_necessary: true)
variant = Spree::Variant.find(params[:variant_id])
quantity = params[:quantity].to_i
options = params[:options] || {}
# 2,147,483,647 is crazy. See issue #2695.
if quantity.between?(1, 2_147_483_647)
begin
order.contents.add(variant, quantity, options)
rescue ActiveRecord::RecordInvalid => e
error = e.record.errors.full_messages.join(", ")
end
else
error = Spree.t(:please_enter_reasonable_quantity)
end
if error
flash[:error] = error
redirect_back_or_default(spree.root_path)
else
respond_with(order) do |format|
format.html { redirect_to cart_path }
end
end
end
Please help me out here.
You need to ensure the values of variant, quantity and options before sending them to spree.
The fact that you get this error could be considered as a bug on their side, since you'd expect a nice error message saying "variant is nil" or the like.
To fix your problem though, I'd check that these values are valid ones before sending them to spree.
For future views about this issue.
Check if the Variant cost_currency attribute is the same that is configured in Spree. You can check it in a rails console doing:
Spree::Config.get(:currency)
Sometimes it happens when spree is initialized with some currency by default and then the default currency is changed.

Rails - Updating Boolean Attribute in a model on Create

I'm creating an app that lets users purchase items from an online store. I followed the RailsCasts episodes, and built my OrdersController like so.
def create
#order = current_cart.build_order(order_params)
#order.ip_address = request.remote_ip
if #order.save
if #order.purchase
Item.where(email: Order.last.email).last.purchased == true
PurchaseMailer.confirmation_email(Item.last.email).deliver
flash[:notice] = "Thanks for your purchase"
redirect_to root_path
else
flash[:danger] = "Something was wrong"
redirect_to :back
end
else
render :action => 'new'
end
end
I recently decided to add an attribute to my items, which says whether or not they've been purchased or not. Items in the cart have not yet been purchased. I created a migration, giving all items a purchased attribute, that is a boolean.
By default, items are not purchased, so the default value is false.
class AddPurchasedToItem < ActiveRecord::Migration
def change
add_column :items, :purchased, :boolean, :default => false
end
end
That's why I added this line of code to my Orders#Create action.
Item.where(email: Order.last.email).last.purchased == true
Here I was setting the value of purchased from false to true. However, when I load up rails console
Item.last.purchased
=> false
It looks like the value still isn't being stored
As another response points out, you're using the == to assign a value, which isn't right. You need = instead.
And you have to save an item after you assign a value to it.
An example:
conditions = {email: Order.last.email} # using your conditions
item = Item.find_by(conditions)
item.purchased = true
item.save # this is what you're missing
Item.find(item.id).purchased # will be true
Another way to update is the following:
item.update_attribute(:purchased, true)
Yet another way is to call update_all on the ActiveRecord::Relation object like so:
# update all items that match conditions:
Item.where(conditions).update_all(purchased: true)
Which method you choose may depend on the scenario as update_all doesn't run the callbacks you specify in the model.
In your case however, all you're missing is the item.save line.
Item.where(email: Order.last.email).last.purchased == true
You're using a == operator to try to assign a value. Try using = instead.

Rails - 'can't dump hash with default proc' during custom validation

I have 2 models. User and Want. A User has_many: Wants.
The Want model has a single property besides user_id, that's name.
I have written a custom validation in the Want model so that a user cannot submit to create 2 wants with the same name:
validate :existing_want
private
def existing_want
return unless errors.blank?
errors.add(:existing_want, "you already want that") if user.already_wants? name
end
The already_wants? method is in the User model:
def already_wants? want_name
does_want_already = false
self.wants.each { |w| does_want_already = true if w.name == want_name }
does_want_already
end
The validation specs pass in my model tests, but my feature tests fail when i try and submit a duplicate to the create action in the WantsController:
def create
#want = current_user.wants.build(params[:want])
if #want.save
flash[:success] = "success!"
redirect_to user_account_path current_user.username
else
flash[:validation] = #want.errors
redirect_to user_account_path current_user.username
end
end
The error I get: can't dump hash with default proc
No stack trace that leads to my code.
I have narrowed the issue down to this line:
self.wants.each { |w| does_want_already = true if w.name == want_name }
if I just return true regardless the error shows in my view as I would like.
I don't understand? What's wrong? and why is it so cryptic?
Thanks.
Without a stack trace (does it lead anywhere, or does it just not appear?) it is difficult to know what exactly is happening, but here's how you can reproduce this error in a clean environment:
# initialize a new hash using a block, so it has a default proc
h = Hash.new {|h,k| h[k] = k }
# attempt to serialize it:
Marshal.dump(h)
#=> TypeError: can't dump hash with default proc
Ruby can't serialize procs, so it wouldn't be able to properly reconstitute that serialized hash, hence the error.
If you're reasonably sure that line is the source of your trouble, try refactoring it to see if that solves the problem.
def already_wants? want_name
wants.any? {|want| want_name == want.name }
end
or
def already_wants? want_name
wants.where(name: want_name).count > 0
end

Is it possible to have params[:customer] created in index action (rails 3.2.12)?

In our customer model (rails 3.2.12), a method find_customers is defined as follows:
def find_customers
customers = Customerx::Customer.scoped
customers = customers.where("sales_id = ?", sales_id_s) if sales_id_s.present?
customers
end
The sales_id_s is passed in via params[:customer][:sales_id_s] through a view form. We want to use the same find_customers method to return customers in customers controller index action. The code is:
def index
if has_index_individual_right?('customerx_customers')
params[:customer][:sales_id_s] = session[:user_id]
customer = Customerx::Customer.new(params[:customer])
#customers = customer.find_customers
else
......
end
......
end
However the code params[:customer][:sales_id_s] = session[:user_id] causes the error: undefined method[]=' for nil:NilClass`. In debug, params[:customer] returns nil.
Is there a way to create params[:customer] object in index action so we can call the model method find_customers?
Thanks for the help.
You can ensure it exists (and is a Hash) by using this params[:customer] ||= {}

Resources