Trying to insert an array into a column - ruby-on-rails

I want to add every cart item into a column (text box) but i can't seem to use "<<" which is a bitwise operator. Is there a way to add every cart item for the order so all the items will appear in the "products" column.
class OrdersController < ApplicationController
before_filter :extract_shopping_cart, :only => [:new, :show]
def new
#order = Order.new
#order.total = #shopping_cart.total
#order.sub_total = #shopping_cart.subtotal
#order.sales_tax = #shopping_cart.taxes
#shopping_cart.shopping_cart_items.each do |cart|
#order.products << cart.item
end
respond_to do |format|
format.html # new.html.erb
format.json { render json: #order }
end
end
def extract_shopping_cart
shopping_cart_id = session[:shopping_cart_id]
#shopping_cart = session[:shopping_cart_id] ? ShoppingCart.find(shopping_cart_id) : ShoppingCart.create
session[:shopping_cart_id] = #shopping_cart.id
end
EDIT: #shopping_cart is from the gem acts_as_shopping_cart
My Order model is as follows
class Order < ActiveRecord::Base
# attr_accessible :title, :body
attr_accessible :total, :sub_total, :sales_tax, :products
belongs_to :user
end
I have an error:
undefined method `<<' for nil:NilClass
Sample code: https://github.com/atbyrd/Bootstrapped_Devise

Check the relationship between Order and Product. The way you're writing it, it looks like Order has_many products and Product can belong to many Orders. I don't see that reflected in your Order model.
In other words, you would have to use has_and_belongs_to_many, like:
class Order < ActiveRecord::Base
attr_accessible :total, :sub_total, :sales_tax, :products
has_and_belongs_to_many :products
belongs_to :user
end
class Product < ActiveRecord::Base
has_and_belongs_to_many :orders
end
The guide does a great job of describing how this works with charts and everything.

Instead of making products a column, it's probably better to add a has_and_belongs_to_many relationship between orders and products so that Rails will have by default an
order.products
array and also a
product.orders
array, where "order" and "product" refer to an instantiated Order or Product with a unique id. This also makes filtering by order or product easy because say you want all the products for a specific order, you could do so by doing something like
#products = Order.find(session[:some_id]).products
to find all products for the order with the specified id, and you could do a similar thing for the products.orders array. Hopefully this helps.

Related

Rails has to and belongs to many correct rails association?

I'm setting up my rails association for an app and I'm not sure if my associations are correct for my use case. The use case is: A product can be added once by a user. Once created other users can then add the same product to their own "feed" within the app. I want to be able to do User.products to list all of a users products. And for products I want to be able to do something like Product.where(id: 2).users to list all of the users that have added the product. I'm currently using a has_and_belongs_to_many association but I think that this is incorrect for what I am trying to achieve?
User model: has_and_belongs_to_many :products
Product model: has_and_belongs_to_many :users
add_index "products_users", ["product_id"], name: "index_products_users_on_product_id"
add_index "products_users", ["user_id"], name: "index_products_users_on_user_id"
Do this:
#app/models/user.rb
class User < ActiveRecord::Base
has_many :created_products, class_name: "Product", foreign_key: :user_id #-> created product
has_and_belongs_to_many :products #-> list of products
end
#app/models/product.rb
class Product < ActiveRecord::Base
belongs_to :user #-> created the product
has_and_belongs_to_many :users #-> list of users
end
You'll need to add the appropriate foreign_key to your User model (user_id in the Product model for the belongs_to :user association) --
--
If your has_and_belongs_to_many relationship is working already, the above should be sufficient.
If not, you need to look up this documentation to see how it works, and then create a join table called products_users (which is populated with the appropriate data):
$ rails g migration CreateProductsUsers
#db/migrate/create_products_users______.rb
class CreateProductsUsers < ActiveRecord::Migration
def change
create_table :products_users, id: false do |t|
t.references :product
t.references :user
end
end
end
$ rake db:migrate
It will allow you to create a single product for a user (IE the Product object will have a direct association with the user who created it). The Product and User models will also be joined with the habtm relationship.
In your controllers, you could use the following:
#config/routes.rb
resources :products #-> url.com/products
scope "profile" do
resources :products, only: :index #-> url.com/profile/products
end
This will allow you to use the following:
#app/controllers/products_controller.rb
class ProductsController < ApplicationController
before_action :product, only: :edit
def index
#products = current_user.products #-> if you're using Devise
end
def edit
#product = current_user.created_products.find params[:id]
end
def new
#product = current_user.created_products.new
end
def create
#product = current_user.created_products.new product_params
#product.save
end
private
def product
redirect_to root_path, notice: "This is not your product" unless current_user.products.exists? params[:id]
end
def product_params
params.require(:product).permit(:x, :y, :z)
end
end
To be able using has_and_belongs_to_many create association, you must create one temperator table container 2 column are product_id, user_id
you can refer
http://apidock.com/rails/ActiveRecord/Associations/ClassMethods/has_and_belongs_to_many
http://guides.rubyonrails.org/association_basics.html#the-has-and-belongs-to-many-association

Use controller action to retrieve data from one model and save data to another model - Rails 4

CartItem Controller and CartItem model handle adding items to CartItems table. Cart view is rendered by calling CartItem model and controller. When clicking ‘Checkout’ I would like to transfer all items saved for a given card in the CartItem table to the OrderItem table.
When clicking ‘Checkout’ on the cart view page the following things should happen:
Call Orders controller from Cart view
<%= button_to "Checkout", controller: 'orders', action: 'create' %>
Orders Controller
def create
#order = Order.new
if logged_in?
#order[:user_id] = current_user.id #This works
end
#Need help: call Order_Items_Controller create action
if #order.save
flash[:success] = "Order created"
else
flash[:danger] = "Failed"
end
redirect_to checkout_address_path
end
OrderItems Controller
def create
#retrieve all records from Cart_Items where cart_id matches cookies[:cart_id]
#order_item = #order.order_items.build!(CartItem.where(:cart_id => cookies[:cart_id]))
#Need help: add order_id for current order to each record
#Need help: save the cart_items to the order_items table and handle exceptions
end
Orders Model
class Order < ActiveRecord::Base
has_many :order_items
end
OrderItems Model
class OrderItem < ActiveRecord::Base
belongs_to :order
validates :order_id, presence: true
end
Why do I want to do this? Once an order is successfully processed the corresponding CartItems data will be deleted, so that the card is empty. OrderItems stores the data for completed orders, so that shoppers can view order history online.
Have you thought about the setup of your models/data structure?
Specifically, duplicating data in one model to another is highly inefficient. You'll be MUCH better using a foreign_key to link your Order model to your cart:
#app/models/cart.rb
class Cart < ActiveRecord::Base
#stores cart items for processing
belongs_to :order
has_many :cart_items
end
#app/models/order.rb
class Order < ActiveRecord::Base
#stores final values (IE delivery service id, cart id, payment id etc)
belongs_to :user
belongs_to :delivery
belongs_to :payment
has_one :cart
end
This way, you'll be able to call the following:
#app/controllers/carts_controller.rb
class CartsController < ApplicationController
def checkout
#cart = current_user.cart #-> or however you call it
#order = #cart.order.new order_params
if #order.save
#-> remove cart from session etc etc
end
end
private
def order_params
params.require(:order).permit(:delivery_id, :user_id, :payment_id)
end
end
Obviously very high-level, but quite descriptive -- an Order becomes a glorified join model, allowing you to compile a "cart" with the relative quantities & items, whilst using the Order to manage the delivery and payments etc.

rails adding tags to controller

I am implementing a basic tagging feature to my app. New to rails.
I have a listings model and I am working in the listings_controller # index. When the user goes to the listing page and sets the :tag param I want #users only to hold the users which match the tag.
So if they goto www.example.com/listings?tag=foo only pages which have been tagged with foo are loaded. This is what I have come up with so far but there is several problems with it.
def index
if params[:tag]
#id = Tag.where(:name => params[:tag]).first.id
#listingid = Tagging.where(:tag_id => #id)
#listingid.each do |l|
#users = User.find(l.listing_id)
end
else
#users = User.all
end
end
I am not sure how to loop and add each found user to #users. I think I may be going about this whole thing the wrong way.. My tag/tagging models look as follows:
tag.rb
class Tag < ActiveRecord::Base
has_many :taggings
has_many :listings, through: :taggings
end
tagging.rb
class Tagging < ActiveRecord::Base
belongs_to :tag
belongs_to :listing
end
Taggings has the following colums:
id, tag_id, listing_id
Tags has the following columns:
id, name
Any guidance would be appreciated, been trying to fix this for a while with no luck.
Trying with
def index
#tag = Tag.where(:name => params[:tag]).first
if #tag
#listings = #tag.listings.includes(:user)
#users = #listings.map{|l| l.user}
else
#users = User.all
end
end

get name of object following 2 time a relationship (2x has_many)

I have an author, who writes products, which are placed in groups.
What I want to do is to list the groups that an author is involved into.
So, I have first to follow the link from author to products, which works with :
#author = Author.find(params[:id])
#products = #author.products
which gives lot of products :-) Then I have to find (all) the groups that are linked to all of the products (because a group can contain a lot of products, I have already a has_many link with group_id column in the product table)
But when I try to write something as
#groups = #author.products.groups
I get the error : undefined method `groups' for # Class:0x000000032a2198
Why ?
Here is the model, where only the "through" clauses seem not to work ?
class Author < ActiveRecord::Base
has_and_belongs_to_many :products
has_many :groups, :through => :products
end
class Product < ActiveRecord::Base
belongs_to :group
has_and_belongs_to_many :authors
end
class Group < ActiveRecord::Base
has_many :products, :dependent => :destroy
has_many :authors, :through => :products
end
Thanks !
Edit : I found an ugly way to do what I want. But is there no better RoR way ??
def show
#author = Author.find(params[:id])
#products = #author.products
#groups = []
#products.each do |product|
group = Group.find(product.group_id)
unless #groups.include?(group)
#groups << group
end
end
end
As far as I know there's no way to do it in a Rails way. First, here's how to make what you have more "Railsy":
def show
#author = Author.find(params[:id])
#products = #author.products
#groups = []
#products.each do |product|
unless #groups.include?(product.group)
#groups << group
end
end
end
But a shorter way would be:
#products.map(&:group).uniq
Quick explanation of what it's doing. First it's using the symbol to proc shorthand that was introduced in Rails 1.1 (http://blog.hasmanythrough.com/2006/3/7/symbol-to-proc-shorthand). That builds an array of groups. Then b/c, in your question, you are checking for uniqueness (using include?) I call .uniq which weeds out any duplicates.
I also found another way to do this :
#user = User.find(params[:id])
#groupcollect = []
#user.products.each { |e| #groupcollect << e.group_id} # collect group_id for all products
#mygroups = Group.find(#groupcollect.uniq) # gets the groups for all group_id, unique
:-)

How to call a variable through the find method

I'm new to ruby on rails and here is the problem:
I'm trying to get the client name inside a loop about the car information. The car data holds an column called "belongs_to" which is the ID of the client.
The important line: <td><%= #client.find(car.belongs_to) %></td>
The controller:
def index
#cars = Car.all
#client = Client.all
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #cars }
end
end
How would you guys do this?
You would use Models to achieve this:
class Car < ActiveRecord::Base
belongs_to :client
end
class Client < ActiveRecord::Base
has_many :cars
end
and in your View:
#car.client
EDIT
or the other way round:
#client.cars
# to iterate over them:
#client.cars.each do |car|
# do something with car
end
belongs_to is not a very good column name. There is an association type called "belongs_to" where you can establish a relationship between models, where one of them "belongs_to" another model, such as:
class Car < ActiveRecord::Base
belongs_to :client # there is a column on the cars table called "client_id"
end
and
class Client < ActiveRecord::Base
has_many :cars
end
Then you can do:
client = car.client
Take a look at Ruby on Rails Guides - A Guide to Active Record Associations
Try
Client.find(car.belongs_to)
What you really want to do, though is have your Car model have something like this
belongs_to :client
And your Client model have
has_many :cars
Then you can simply call #car.client to get what you want.
I guess you could do something like:
#cars.each do |car|
car.client
end
and in car model, I guess you alredy have:
belongs_to :client

Resources