Rails saving array with the duplicated elements - ruby-on-rails

I'm populating an array with multiple elements (some of then are equals, thats what I want). My code is something like this:
def create
#order = Order.create()
#order.table = Table.find_by(:number => params['table'][0])
#products ||= []
#qtd = []
Product.all.each do |product|
params['order'].each_pair do |ordered|
if(product.id.to_s == ordered.first)
for i in 0..ordered.second[0].to_i
#order.products << product
#order.save
end
end
end
end
binding.pry #here the #order.products is the way I want to
if #order.save
flash[:success] = "Pedido criado com sucesso."
redirect_to tables_path
else
flash[:danger] = "Erro ao criar pedido."
render :new
end
end
But When I go to rails console and do Order.last.products he dosen't show me de duplicated elements like I saved on my controller. Whats happening?

Well in your case you should be sending order information from client to server like
"order"=>{"line_items_attributes"=>{"0"=>{"quantity"=>"4", "id"=>"127"}}}
Instead of repeating the product id in the list, your should implement a concept of line items in your system. Line Items are the objects representing items that are added to your shopping cart and instead of repeating the product_id you can use term quantity.
Now you can have separate model called LineItem. Order can have many LineItems. LineItem has many products.
For more info see What is a "order line"?
For current Implementation:
<< method does not allow duplicate entries. It filters out the duplicates. Its basically relates products with order since order can have multiple products via some_table. It cannot relate same product to the order twice.
My suggestion would be, create a string field(column) called products and add the serialized array of product ids.
order.products = [1, 1, 3, 4,4,4].to_s
while accessing you de-serialize.

Related

Rails saving arrays to separate rows in the DB

Could someone take a look at my code and let me know if there is a better way to do this, or even correct where I'm going wrong please? I am trying to create a new row for each venue and variant.
Example:
venue_ids => ["1","2"], variant_ids=>["10"]
So, I would want to add in a row which has a venue_id of 1, with variant_id of 10. And a venue_id of 2, with variant_id of 10
I got this working, and it's now passing in my two arrays. I think I am almost there I'm not sure the .each is the right way to do it, but I think that I'm on the right track haha. I have it submitting, however, where would I put my #back_bar.save? because this might cause issues as it won't redirect
Thanks in advance.
def create
#back_bar = BackBar.new
#venues = params[:venue_ids]
#productid = params[:product_id]
#variants = params[:variant_ids]
# For each venue we have in the array, grab the ID.
#venues.each do |v|
#back_bar.venue_id = v
# Then for each variant we associate the variant ID with that venue.
#variants.each do |pv|
#back_bar.product_variant_id = pv
# Add in our product_id
#back_bar.product_id = #productid
# Save the venue and variant to the DB.
if #back_bar.save
flash[:success] = "#{#back_bar.product.name} has been added to #{#back_bar.venue.name}'s back bar."
# Redirect to the back bar page
redirect_to back_bars_path
else
flash[:alert] = "A selected variant for #{#back_bar.product.name} is already in #{#back_bar.venue.name}'s back bar."
# Redirect to the product page
redirect_to discoveries_product_path(#back_bar.product_id)
end
end # Variants end
end # Venues end
end
private
def back_bar_params
params.require(:back_bar).permit(:venue_id,
:product_id,
:product_variant_id)
end
as i said in comments
this is untested code and just showing you how it's possible to do with ease.
class BackBar
def self.add_set(vanue_ids, variant_ids)
values = vanue_ids.map{|ven|
variant_ids.map{|var|
"(#{ven},#{var})"
}
}.flatten.join(",")
ActiveRecord::Base.connection.execute("INSERT INTO back_bars VALUES #{values}")
end
end
def create
# use in controller
BackBar.add_set(params[:venue_ids], params[:variant_ids])
# ...
end

Best way to reindex objects in Ruby after jQuery.sortable()

I have objects with a 'position' defined. I 'm moving one object (using jQuery Sortable), then I need to reindex the position of each object in that list (I want to keep them in order 0,1,2...n)
Basically we have a ProductLine model that contains Products (using act_as_list for convinience).
First, swap the position of the previous object and the new object (the one we just dropped here):
def sort
#product = Product.find(params[:id])
if(params.has_key?(:next_id))
#next_product = Product.find(params[:next_id])
end
if(params.has_key?(:prev_id))
#prev_product = Product.find(params[:prev_id])
end
if #prev_product.blank?
#product.move_to_top
elsif #next_product.blank?
#product.move_to_bottom
else
#product.insert_at(#prev_product.position)
end
#product.save
reindex #product.product_line_id
render json: #products
end
This is the reindex function that ensures they are sequential:
def reindex(product_line_id)
#products = Product.where(product_line_id: product_line_id).order(position: :asc)
#products.each_with_index { |p, index|
p.position = index
p.save
}
end
I'm quite new to the Ruby language and I'm sure there are several cleaner, more efficent ways of doing this?

Take random ids, then store those random ids into the db

so I'm working on a code snippet that essentially takes out 35 random ids from the table List.
What I would like to do to find the ids that got randomly generated, store them into a database called Status.
The purpose is to avoid duplication the next time I get a new 35 random ids from the List. So I never get the same random id twice.
Here's what I've tried, but been unsuccessful to get working.
#schedule = current_user.schedules.new
if #schedule.save
#user = User.find(params[:id])
Resque.enqueue(ScheduleTweets, #user.token)
#schedule.update_attribute(:trial, true)
flash[:notice] = "success"
redirect_to :back
else
flash[:alert] = "Try again."
redirect_to :back
end
and the worker:
def self.perform(user_token)
list = List.first(6)
#status = list.statuses.create
list.each do |list|
Status.create(list_id: "#{list}")
if list.avatar.present?
client.create_update(body: {text: "#{list.text}", profile_ids: profile_ids, media: { 'thumbnail' => 'http://png-1.findicons.com/files/icons/85/kids/128/thumbnail.png', 'photo' => 'http://png-1.findicons.com/files/icons/85/kids/128/thumbnail.png' } })
end
end
end
however the Status.create(list_id: #list) doesn't work.
Does anybody have any idea what is going on, and how I can make the list_ids get saved successfully to Status?
It's also associated:
list has many statuses, and status belongs to list
The following line of code is wrong:
Status.create(list_id: "#{list}") # WRONG
In your case the list variable is a List instance. And you're passing its string version to list_id which expects an integer.
Do this:
Status.create(list_id: list.id)
Or this:
list.statuses.create
I think the following will also work:
Status.create(list: list)

Adding and Accessing Multiple Session Variables in Rails

I need a way to change the status of products in my store to sold once a purchase is completed...
I use the following code:
if #order.purchase #I use active merchant's purchase method on compiled order
update_product_status #method explained below
end
Before a product is copied as a line_item this code is run:
#product = Product.find(params[:product_id]) #line_item belongs to product and cart
session[:pending_purchase] = #product.id #stores ID number into session
So that later I can pull the ID, for the update_product_status code:
def update_product_status #used to update boolean 'sold' status on product
product = session[:pending_purchase]
#sold_product = Product.find(product)
#sold_product.update(:sold = true) #not sure if this syntax is correct
end
A problem may present itself if someone buys two items. Will the ID in :pending_purchase get over written if a second line_item is created and added to the cart? How would I access both variables and make sure both items now have a 'sold = true' attribute?
the simplest way is that stores product's id as an array.
#product = Product.find(params[:product_id])
(session[:pending_purchase] ||= []) && (session[:pending_purchase] << #product.id )
and your will find more products when you use it:
#products = Product.find(session[:pending_purchase])
#products.each do |p|
.........
end

How to show flash message of newly created resources?

Lets say I have a Product model and my controller allows the creation of 5 new products all at once. What I do right now is render back to the same page but what I want to do is also render in the flash which products have been created. So it would say:
Successfully created: Milk, Soup, Cheese, Bread, Candy
instead of
Successfully created Products
How would this be done?
Something like this should work:
redirect_to :back, notice: "Succesfully created: #{#created_products.map(&:name).join(', ')}"
Assuming #created_products is an array of the products you just created and they each have an attribute called name.
Oh and of course you need this in your html:
<div class="notice"><%= notice %></div>
Just do this in your controller. You probably have a create action where you actually create these objects, and they problem have a name attribute or something, right? So when you create the objects, save them in an array, then use the map and join methods to put them together. Something like this:
def create
successful = []
# loop through the parameters
obj = MyModel.new(...)
if obj.save
successful << obj
end
# end loop
flash[:notice] = "Succesfully created: #{successful.map(&:name).join(', ')}"
redirect_to my_model_path
end
Map runs the method you pass in, so name, on each of the memebrs of the array and returns an array whose contents are the results of that method: in other words, you get an array of all their names. Join puts them together separated by whatever string you put in. So you'd get something like "Milk, cheese".

Resources