Rails select has_many though get the right Id - ruby-on-rails

I'm trying to pass the size of a product to a order with select. the product has many sizes with has_many though.
the size.id on the orger page did not match with the size.id that i choose on the product page.
someone know why?
for exemple if choose product size.id(2) on the order page show size.id(4)
Size Model
attr_accessible :size
has_many :orders
has_many :sizeship
has_many :products, :through => :sizeship
Product Model
has_many :orders
has_many :sizeships
has_many :sizes, through: :sizeships
Order Model
belongs_to :cart
belongs_to :product, touch: true
belongs_to :size
Cart Model
belongs_to :user
has_many :orders
Product Controller
def show
#product = Product.cached_find(params[:id])
#sizes_for_dropdown = #product.sizes.collect { |s| [s.size, s.id] }
end
Cart Controller
def add
product = Product.find(params[:id])
if product
if product.buyable?(current_user)
current_user.cart = Cart.new #if current_user.cart.nil?
size = product.sizes.find_by_id(params[:size_id])
quantity = params[:quantity].to_i > 0 ? params[:quantity].to_i : 1
order = current_user.cart.orders.find_by_product_id_and_status_and_size_id(product.id, nil, product.sizes.nil? ? nil : product.sizes.find { |l| l.id } )
if order.nil? # create new order
order = Order.new
order.product = product
order.size = product.sizes.find { |k| k.id }
current_user.cart.orders << order
else # increase quantity
order.quantity += quantity
order.save
end
redirect_to product_path(product)
flash[:success] = "Success"
else
redirect_to product_path(product)
flash[:error] = " Error"
end
else
redirect_to :shop, flash[:error] = 'Error'
end
end
Log
Started POST "/carts/add/yy" for 127.0.0.1 at 2016-11-17 00:11:16 -0200
Processing by CartsController#add as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"Hf7eLJPojw+u/HCGuQtAVzADC7v0jpkw5mJ0sCmx0u4=", "score"=>"", "quantity"=>"1", "size_id"=>"1", "commit"=>"add to basket", "id"=>"yy"}
Redirected to http://localhost:3000/products/yy
Completed 302 Found in 3471.4ms

Related

Nested model into another nested model asking for first model ID when save

We have a Rails 5.2 code that have this structure:
Contract -> Client -> Account
Contract have a Client
Client have a Account
Contract have the Client Account to.
When we save in the Contract Controller we get and error that ask for the Contract ID on the Account Model.
All the forms are using nested into nested, nested attributed is ok.
/contratos_controller.rb
class ContratosController < ApplicationController
layout "contratouxs"
def new
#contrato = Contrato.new
#produtos = Produto.all
cliente = #contrato.build_cliente
cliente.build_logradouro
cliente.build_contabanco
end
def create
#contratoux = Contrato.new(contratoux_params)
respond_to do |format|
if #contratoux.save
$k = #contratoux.vencimento.to_i
$n = (1..#contratoux.produto.parcelas)
$n.each{|n|
#fin = Financeiro.create(contrato_id: #contratoux.id, parcela: n, valor: #contratoux.produto.valor1, data: Date.new(2018, 12, $k).next_month(n))
#fin.save!
}
format.html { redirect_to contratouxs_final_path, notice: 'Contrato foi criado com sucesso.' }
format.json { render :show, status: :created, location: contratouxs_path }
else
#contratoux.errors.full_messages
format.html { redirect_to contratouxs_path, alert: 'Contrato não foi criado com sucesso.' }
format.json { render json: #contratoux.errors, status: :unprocessable_entity }
end
end
end
def geracontrato
#contrato = Contrato.last
respond_to do |format|
format.pdf { render template: 'contratouxs/contratoux', pdf: 'Contrato'}
end
end
def final
end
private
# Use callbacks to share common setup or constraints between actions.
# def set_contrato
# #contrato = Contrato.find(params[:id])
# end
# Never trust parameters from the scary internet, only allow the white list through.
def contrato_params
params.require(:contrato).permit(:valor, :data, :resalva, :termosguarda, :assinaturaeletronica, :datainicio, :datafim, :periodo, :multiplicador, :quantdias, :tiposeguro, :categoriaclausulas, :quantproduto, :revendedor_id, :agente_id, :cliente_id, :produto_id, :user_id, :status ,:vencimento, :cliente, cliente_attributes: [:nome, :tel1, :email1, :tax, :nascimento, :profissao, :faixarenda, :expostapolicamente, :revendedor_id, :agente_id, logradouro_attributes: [:cep, :endereco, :numero, :bairro, :cidade, :uf], contabanco_attributes: [:banco, :conta, :digitoconta, :agencia, :digitoagencia, :revendedor_id, :agente_id, :cliente_id, :contrato_id]])
end
end
Model /contrato.rb
class Contrato < ApplicationRecord
belongs_to :revendedor
belongs_to :agente
belongs_to :cliente
belongs_to :produto
belongs_to :user
has_many :financeiros
has_one :contabanco
accepts_nested_attributes_for :cliente
end
Model /cliente.rb
class Cliente < ApplicationRecord
belongs_to :agente, optional: true
belongs_to :revendedor, optional: true
belongs_to :user, optional: true
has_one :logradouro, dependent: :destroy
has_one_attached :image
has_many :contratos
has_one :contabanco
validates :nome, :tel1, :email1, presence: true
accepts_nested_attributes_for :logradouro
accepts_nested_attributes_for :contabanco
end
Model /contabanco.rb (is the Account Model)
class Contabanco < ApplicationRecord
belongs_to :revendedor
belongs_to :agente
belongs_to :cliente
belongs_to :contrato
end
The view form /_form.html.erb
<%= form_with(model: contratoux, url: contratouxs_path, local: true, id: "form-cliente") do |form| %>
....
<%= form.fields_for :cliente do |cli| %>
<%= cli.fields_for :contabanco do |conta| %>
....
<% end %>
<% end %>
<% end %>
When we save (or save!) the Rails error ask for the Contrato ID
ActiveRecord::RecordInvalid in ContratosController#create
The validation fail: Cliente contabanco contrato is need
Rails has a keyword, autosave, which you can use on your belongs_to relationships. This should solve most of this for you.
Here is an answer to another question which explains this nicely. https://stackoverflow.com/a/38068935/1146473

Rails and arrays

Here is problem :
Order object has two attributes which defined as array of string (list_of_products, quantity_of_product). Also Order has_many line_items and has_many products through line_items.
This is show_receipt action in Public controller:
def show_receipt
#order = Order.find(params[:id])
#order.sum = 0.0
#order.quantity = 0
#order.quantity_of_product = []
#order.list_of_products = []
#order.line_items.each do |item|
#product = Product.find(item.product_id)
#order.list_of_products << #product.name
#order.sum += (item.quantity*item.price).to_d
#order.quantity += item.quantity
#order.quantity_of_product << item.quantity.to_s
#product.unite = #product.unite - item.quantity
#product.save
end
#order.save
end
it works fine, when I debug(#order) in the view of show_receipt action I can see those two arrays (list_of_products and quantity_of_product). Both are NOT empty. But when I debug(#order) in the view of ../orders/#order there are two arrays but one of them (list_of_products) is empty and the other one (quantity_of_product) is NOT empty?
Here is Order class:
class Order < ActiveRecord::Base
belongs_to :customer
has_many :line_items
has_many :products, :through => :line_items
accepts_nested_attributes_for :line_items
accepts_nested_attributes_for :products
end
Any idea?

How do I update Nested Attributes in Rails without accepts_nested_attributes_for?

I'm working on a project for a class where I have a very large form with Nested Models. Here are the models that are important to the form, as well as their associations:
Course: has_many :time_blocks, has_many :tags, through: :taggings, belongs_to :institution, has_many :roles, has_many :users, through: :roles
TimeBlock: belongs_to :course
Tag: has_many :taggings
Tagging: belongs_to :tag, belongs_to :taggable_type
Institution: has_many :courses, has_many :users
Role: belongs_to :course, belongs_to :user
I am able to create the Nested Form correctly, but I can't get the Nested Models to update correctly. Here is the controller, the form is very long, but I have provided the params for the Nested Models. Note, I cleared out the values from the params, but some of the params have ID values because they exist in the db. I've also included the CoursesHelper to show the helper methods I'm using in the controller.
app/controllers/courses_controller.rb
def new
#course = current_user.courses.new
#course.institution = Institution.new
4.times { #course.tags.build }
7.times { #course.time_blocks.build }
end
def create
#course = Course.new(params[:course])
#course.institution = Institution.new(params[:institution])
filled_tags = set_tags(params[:tag])
#course.tags.build(filled_tags)
filled_time_blocks = set_time_blocks(params[:time_block])
#course.time_blocks.build(filled_time_blocks)
if #course.save
Role.create!(
user_id: current_user.id,
course_id: #course.id,
title: 'instructor'
)
redirect_to #course
else
(4 - filled_tags.count).times { #course.tags.build }
(7 - filled_time_blocks.count).times { #course.time_blocks.build }
flash.now[:errors] = #course.errors.full_messages
render :new
end
end
def edit
end
def update
filled_time_blocks = set_time_blocks(params[:time_block])
filled_time_blocks.each do |time_block|
#course.time_blocks.update_attributes(time_block)
end
filled_tags = set_tags(params[:tag])
filled_tags.each { |tag| #course.tags.update_attributes(tag) }
# #course.tags.update_attributes(filled_tags)
# #course.time_blocks.update_attributes(filled_time_blocks)
fail
if #course.update_attributes(params[:course])
redirect_to #course
else
flash.now[:errors] = #course.errors.full_messages
render :edit
end
end
app/helpers/courses_helper.rb
def set_time_blocks(entries)
result = []
days = entries[:day_of_week].reject! { |day| day.blank? }
days.each do |day|
time_block = {}
time_block[:day_of_week] = day
time_block[:start_time] = entries[day][:start_time]
time_block[:end_time] = entries[day][:end_time]
time_block[:id] = entries[day][:id]
result << time_block
end
result
end
def set_tags(entries)
[].tap do |tags|
entries.each do |entry|
tags << entry unless entry.values.all?(&:blank?)
end
end
end
def find_course
if params.include?(:id)
#course = Course.find(params[:id])
else
flash[:notice] = "Sorry, Could Not Find Course."
redirect_to current_user
end
end
TimeBlock Params
{"sun"=>{"start_time"=>"", "end_time"=>"", "id"=>""}, "mon"=>{"start_time"=>"", "end_time"=>"", "id"=>"3"}, "tue"=>{"start_time"=>"", "end_time"=>"", "id"=>"4"}, "wed"=>{"start_time"=>"", "end_time"=>"", "id"=>"5"}, "thu"=>{"start_time"=>"", "end_time"=>"", "id"=>"6"}, "fri"=>{"start_time"=>"", "end_time"=>"", "id"=>"7"}, "sat"=>{"start_time"=>"", "end_time"=>"", "id"=>""}, "day_of_week"=>[]}
Tag Params
[{"name"=>"", "id"=>"4"}, {"name"=>"", "id"=>""}, {"name"=>"", "id"=>""}, {"name"=>"", "id"=>""}]
If you cant make it work with accepts_nested_attributes_for then you'll have to write your own setter method(s) manually. Something like:
class Course < ActiveRecord::Base
def tag_attributes=(tags)
tags.each do |tag|
self.tags.build(tag)
end
end
end
The method name (tag_attributes= in my example) needs to match the key name that the tag params are listed under

Method to merge objects which are similar (differing by quantity)

I need help with a cart object which has_many line_items. If a line_item in the cart is created and it has the same exact attributes as a line_item which is already in the cart I just want to update the pre existing line_items quantity rather than create duplicate objects with separate quantities.
I wrote a few methods in my models to try and make this work but it isn't working. Below is my code:
models
class LineItem < ActiveRecord::Base
attr_accessible :cart_id, :product_id, :quantity, :unit_price, :product, :cart, :color_id, :size_id, :extra_id
belongs_to :cart
belongs_to :product
belongs_to :color
belongs_to :size
belongs_to :extra
validates :quantity, :presence => true
def update_quantity(qty)
quantity += qty
quantity.save
end
def exists_in_collect?(items)
if items.include?(product)
if color == items.color && size == items.sizes && extra == items.extra
return true
end
else
return false
end
end
end
class Cart < ActiveRecord::Base
attr_accessible :purchased_at
has_many :line_items
has_one :order
def where_line_item_with(prod_id)
line_items.where(:product_id => prod_id)
end
end
controller
class LineItemsController < ApplicationController
def new
#line_item = LineItem.new
end
def create
#line_item = LineItem.new(params[:line_item].merge(:cart => current_cart))
if #line_item.exists_in_collect?(current_cart.line_items)
current_cart.where_line_item_with(product.id).update_quantity(#line_item.quantity)
#line_item.destroy!
else
#line_item.save!
#line_item.update_attributes!(:unit_price => #line_item.item_price)
end
redirect_to current_cart_url
end
def update
#line_item = LineItem.find(params[:id])
#line_item.update_attributes(params[:line_item])
redirect_to current_cart_url
end
Any insight is fully appreciated.
1.You should change your where_line_item_with(prod_id) to the following:
def where_line_item_with(prod_id)
line_items.where(:product_id => prod_id).first
end
As the where returns an array and you cannot do update_quantity(#line_item.quantity) on an array.
2.In exists_in_collect?(items) - Here your aim is to find if the items of the cart include the item similar to new item. it should be updated as following:
def exists_in_collect?(items)
items.each do |item|
if color == item.color && size == item.sizes && extra == item.extra && product == item.product
return true
end
end
return false
end

How to duplicate a group of "tasks" that belong to the same model

I'm in rails 3.0 and I'm working on a "project management" app. I'd like to duplicate an Item, which in my case is the "project", and at the same time, duplicate all tasks that belong to that item.
I stuffed my Item model with code I found here: http://www.redmine.org/projects/redmine/repository/revisions/2704/diff/trunk/app/models/project.rb, which seems to do what I want, but I can't make it work for me.
I'd like any help you can offer--general or specific! thanks!
class Task < ActiveRecord::Base
belongs_to :department
belongs_to :item
belongs_to :customer
end
class Item < ActiveRecord::Base
belongs_to :customer
has_many :tasks
def copy(item)
item = item.is_a?(Item) ? item : Item.find(item)
Item.transaction do
# Tasks
item.tasks.each do |task|
new_task = Task.new
new_task.copy_from(task)
self.tasks << new_task
end
self.save
Hook.call_hook(:model_item_copy_before_save, :source_item => item, :destination_item => self)
end
end
def self.copy_from(item)
begin
item = item.is_a?(Item) ? item : Item.find(item)
if item
# clear unique attributes
attributes = item.attributes.dup.except('id')
copy = Item.new(attributes)
copy.enabled_modules = item.enabled_modules
copy.trackers = item.trackers
copy.custom_values = item.custom_values.collect {|v| v.clone}
return copy
else
return nil
end
rescue ActiveRecord::RecordNotFound
return nil
end
end
Another thing--what is the Hook.call_hook...? I can't find any references to that on the web
Look into ActiveResource::Base#clone.
It should probably work something like:
#project = #project2.clone
#project.tasks << #project2.tasks.map(&:clone)
#project.save
EDIT:
In the context of your model you could just have:
def self.copy(item)
newitem = item.clone
newitem.tasks << item.tasks.map(&:clone)
return newitem
end
Then in your controller:
#project = Project.copy(#project_to_copy)
#project.save

Resources