Destroy an object in model file if its missing a condition - ruby-on-rails

How can i destroy this object if its category_attributes(:title) is empty?
def categories_attributes=(categories_attributes)
categories_attributes.values.each do |category_attribute|
category = Category.find_or_create_by(category_attribute)
categories << category
end
end

Try this:
def categories_attributes=(categories_attributes)
categories_attributes.values.each do |category_attribute|
category = Category.find_or_create_by(category_attribute)
if category.title?
categories << category
elsif category.persisted?
category.destroy
end
end
end

Related

How to add a size attribute to shopping cart item

I built a working shopping cart system the other day using Ruby on Rails, and with the guidance of following a tutorial. Now I would like to modify the existing shopping cart item to incorporate the size of a particular item being placed in the cart.
I created a migration file to add a size column to the Products table, and then I started modifying CartItem class, and the Cart class files respectively.
class CartItem
attr_reader :product_id, :quantity, :size
def initialize product_id, quantity = 1, size
#product_id = product_id
#quantity = quantity
#size = size
end
def increment
#quantity = #quantity + 1
end
def product
Product.find product_id
end
def total_price
# puts "Hello cart_item"
product.price * quantity
end
end
class Cart
attr_reader :items
def self.build_from_hash hash
items = if hash["cart"] then
hash["cart"]["items"].map do |item_data|
CartItem.new item_data["product_id"], item_data["quantity"], item_data["size"]
end
else
[]
end
new items
end
def initialize items = []
#items = items
end
def add_item product_id, size
item = #items.find { |item| item.product_id == product_id
item.size == size }
if item
item.increment
else
#items << CartItem.new(product_id, size)
end
end
def empty?
#items.empty?
end
def count
#items.length
end
def serialize
items = #items.map do |item|
{
"product_id" => item.product_id,
"quantity" => item.quantity,
"size" => item.size
}
end
{
"items" => items
}
end
def total_price(shipping_price = 0)
# puts "Hello cart"
#items.inject(0) { |sum, item| sum + item.total_price } + shipping_price
end
end
However, I'm getting the following error,
Because your add_item method should be into two parameter, but your params is hash can't use params[:id, :size] replace params[:id], params[:size] it work.

Ruby: NoMethodError: undefined method `<<' for nil:NilClass

I get the error "NoMethodError: undefined method `<<' for nil:NilClass" when trying to add an object to an empty array. I think it relates to the array being nil instead of empty, and it's not allowing me to append a new object.
The problem occurs with the last line cashier.rule_set.add(apple_rule). Not sure if I am implementing the RuleSet class and initializing #rules correctly.
class Rule
attr_reader :sku, :quantity, :price
def initialize(sku, quantity, price)
#sku = sku
#quantity = quantity
#price = price
end
end
class RuleSet
attr_accessor :rules
def initalize()
#rules = []
end
def add(rule)
#rules << rule
end
def rule_for_sku(sku)
#rules.detect { |r| r.sku == sku }
end
end
class Product
attr_accessor :name, :price, :sku
def initialize(name, price)
puts "Added #{name}, which costs $#{price} to available inventory."
#name = name
#price = price
#sku = (rand(100000) + 10000).to_s
end
end
class Cashier
attr_accessor :rule_set
def initialize
#cart = []
#total_cost = 0
#rule_set = RuleSet.new
end
def add_to_cart(product)
puts "Added #{product.name} to your cart."
#cart << product
end
def in_cart
#cart.each_with_object(Hash.new(0)) {|item, counts| counts[item] += 1}
end
def checkout
self.in_cart.each do |item, quantity|
rule = self.rule_set.rule_for_sku(item.sku)
if rule.present? && quantity >= rule.quantity
total_cost += item.price
end
end
end
end
##Testing
#Initialize list of available products and costs
apple = Product.new("apple", 5)
banana = Product.new("banana", 2)
grape = Product.new("grape", 3)
apple_rule = Rule.new(apple.sku, 3, 12)
cashier = Cashier.new
cashier.rule_set.add(apple_rule)
You have misspelt initialize in your RuleSet class (initalize) so that method isn't being called and #rules is not being set to an empty array.

Rails: how to test if parent has grandchildren present in child model

I (want to) have a method in a parent model (groups) to check if a child (subjects) has children (goals)
groups.rb:
def has_goals?
#answer = []
subjects = self.subjects
subjects.each do |subject|
if subject.try(:goals).present?
#answer << true
else
#answer << false
end
end
if #answer.include?("true")
true
else
false
end
end
I would use this like so -
if group.has_goals?
# do something
else
# do something else
end
at the moment it's not working as it's returning false for everything - whether the subject has goals or not. Any ideas how to get this working?
Check if any of the subjects has at least a goal (subjects.goals should return [] if the subject has no goals):
def has_goals
subjects.any? { |subject| subject.goals.present? }
end
Enumerable#any? reference: http://ruby-doc.org/core-2.0/Enumerable.html#method-i-any-3F

Rails - Object values not being accessible on a attribute writer method

I have a Study model which have many fields, but I'm having troubles with 1
profesion_name
so in my study model I have this
class Study < ActiveRecord::Base
attr_accessible :profesion_related, :profesion_name
attr_accessor :profesion_related
def profesion_related=(id)
if id.present?
if self.study_type_id == 4
if self.country_id == 170
#some code here
else
profesion_parent = Profesion.find(id)
new_profesion = Profesion.create({g_code: profesion_parent.g_code, mg_code: profesion_parent.mg_code, name: self.profesion_name})
self.profesion = new_profesion
end
end
end
end
end
but I'm getting an error on the line that create a Profesion, because self.profesion_name is nil
if in my controller I do this
def create
#study = Study.new(params[:study])
respond_to do |format|
#here
puts #study.to_yaml
if #study.save
.....
end
I will see in the console that profesion_name has a value
but if I do this
class Study < ActiveRecord::Base
...
def profesion_related=(id)
puts self.to_yaml
....
end
end
I can see that self.profesion_name is empty
Why could this be happening?

How to associate instances from different classes in Ruby

I want to be able to initialize a new Car object and pass it a Person object in the parameters, so it can be saved in that Person's #cars array. Currently, I take this approach:
person = Person.new("Michael")
car = Car.new("Honda", "Accord")
person.add_car(car)
person.add_car(Car.new("Ford", "Taurus"))
person.add_car(Car.new("Toyota", "Prius"))
person.display
However, I'd like to be able to create a new car instance and pass it the Person object I want it associated with. For example:
person = Person.new("Michael")
Car.new("Honda", "Accord", person)
Car.new("Toyota", "Camry", person)
Car.new("Chevy", "Tahoe", person)
person.display
Is that even possible?
class Person
attr_accessor :name
def initialize(name)
super
#name = name
#cars = []
end
def display
puts "#{#name} has #{#cars.length} cars"
puts "----------------------------"
#cars.each do |car|
puts "#{car.make} #{car.model}"
end
end
def add_car(car)
#cars.push(car)
end
end
class Car
attr_accessor :make, :model
def initialize(make, model)
#model = model
#make = make
end
def display
puts "#{#make} #{#model}"
end
end
Yes, that is possible, Car#initialize can call methods on its arguments:
class Car
def initialize(make, model, person = nil)
#model = model
#make = make
person.add_car(self) if(person)
end
#...
end
This would be my implementation:
class Car
attr_accessor :make, :model
def initialize(make, model)
self.make = make
self.model= model
end
end
Person class
class Person
attr_accessor :name, :cars
def initialize(name, cars=[])
self.name = name
self.cars = cars || []
end
def add_car(*args)
raise ArgumentError, 'invalid arguments' if (
(args.size > 2 or args.size == 0) or
(args.size == 1 and !args[0].is_a?(Car))
)
new_car = (args.size == 2) ? Car.new(*args) : args[0]
self.cars << new_car
new_car
end
end
Now you can:
person = Person.new("Michael")
car = Car.new("Honda", "Accord")
person.add_car(car)
person.add_car("Ford", "Taurus")
person.add_car("Toyota", "Prius")
person.display
The add_car method creates a new car when make and model are passed as parameters.
Yes, it is possible as mu is too short's answer demonstrated, but that doesn't really make sense in my opinion. Your cars can't be used in any context without a Person, and said parameter contributes no data necessary to construct the Car object.
I would design such an API as follows:
class Person
def initialize(name)
#name = name
end
def cars
#cars ||= Array.new # Equivalent to #cars || #cars = []
end
end
person = Person.new 'Michael'
taurus = Car.new 'Ford', 'Taurus'
prius = Car.new 'Toyota', 'Prius'
person.cars << taurus << prius << Car.new('Honda', 'Accord')
This is a simpler and more direct form of KandadaBoggu's implementation that takes advantage of the Array#<< method in order to naturally associate Cars with a Person, and also doubles as an attribute reader.

Resources