Get value from other model without any association - ruby-on-rails

I have 3 models and tables Products, Customers, Buyers and there are has_and_belongs_to_many relationship among them. And I have another model and table sells. I need to get value from all of the above 3 tables in sells/new page. Do I have to use any association among them? How can I get the values?
I want product_id, product_name, customer_id, customer_name in views/sells/new.html.erb file I don't understand how can I get that

First of all it should be sales table and the Sale model. But anyway, from the view (or helper), you can do:
Product.all # gives you all products
# or fetch just the columns you want:
Product.select( [:id, :name] )
Same goes for customers (i.e. Customer.all etc.).
It's not an orthodox way to do it but it will work. With Erb you'll need <% ... %> or <%= ... %> of course.

Add user_id and product_id to sells table
Class User
has_many :sells
end
Class Product
has_many :sells
end
Class Sells
belongs_to :user
belongs_to :user
end
Then do on sell show page
sell.user_id
sell.user.name
sell.product_id
sell.product.name
Hope this is what you need or least give an idea :)

Related

How do I make an attendance sheet in rails?

I have a Meeting model, view, and controller. Every Meeting, I would like to take attendance of the Members of the club. Each Meeting is also associated with a Tournament.
It seems ideal to me, that each Meeting Entry would store the Tournament_id and attendence for each Member_id. However, if you were to do this, you would need a dynamic column length for the member_ids (one column for each member), which can vary.
Is that possible?
If that is not the best way, what is the best way to store the data?
Currently, I have it where each Meeting.id stores 1 Member's Attendance and the form rolls out all Members for 1 given tournament and a check box for their attendance. However, I don't fully understand how that is working, and I can't figure out how to easily Edit the member's attendance that way.
I got part of the solution of my current functionality from here, but was trying to find out if there is another way to get it fully working.
Thanks
It seems ideal to me, that each Meeting Entry would store the
Tournament_id and attendence for each Member_id. However, if you were
to do this, you would need a dynamic column length for the member_ids
(one column for each member), which can vary.
Big nope. That's not a tenable solution for modeling data in a relational database as the schema would be completely unmaintable and you would end up with a huge amount of columns that almost entirely contain nulls. The SQL queries would also be very crazy.
You instead need to think in terms of each row in a table containing the unique data for each member. In database design this corresponds to the concept First Normal Form.
This is a simplefied example of how you would keep track of attendence*:
class Member
has_many :attendences
has_many :meetings, through: :attendences
end
class Meeting
has_many :attendences
has_many :members, through: :attendences
end
# rails g model attendence member:belongs_to meeting:belong
class Attendence < ApplicationRecord
belongs_to :member
belongs_to :meeting
end
Here attendences is a join table containing the member and meeting ids and we have a many to many assocation between Member and Meeting.
You can then just use the rails form helpers for creating checkboxes from collections together with the member_ids setter / getter created by has_many :members, through: :attendences:
<%= form_with(model: #meeting) do |form| %>
<div class="field">
<%= form.label :member_ids, 'Members in attendence' %>
<%= form.collection_checkboxes :member_ids, #available_members, :id, :name %>
</div>
# ...
<% end %>
In your controller you would then whitelist the member_ids column with a hash key with an empty array as the value:
class MeetingsController < ApplicationController
def new
#meeting = Meeting.new
#available_members = Member.all
end
def create
#meeting = Meeting.new(meeting_params)
if #meeting.save
redirect_to #meeting
else
#available_members = Member.all
render :new
end
end
private
def meeting_params
params.require(:meeting)
.permit(:foo, :bar, :baz, member_ids: [])
end
end
This will permit an array of permitted scalar values such as a list of ids.

Fastest way to get has_many association records in each loop

I have a has_many through association where I have many products which have different prices depending on countries (they can only have one price per country).
The loop I'm trying to do is the following
#product.countries.each do |country|
country.name
# here I want to get the price of this product in that country
end
I want something which does something similiar to country.prices.where(product_id: #product.id).first
I'm sure there is a clean way to right this code without having to use a where. Any idea on how to do this ?
Here is are my models
products
has_many :prices
has_many :countries, through :prices
prices
belongs_to :product
belongs_to :country
belongs_to :currency
countries
has_many :prices
has_many :products, through :prices
You could flip this around and process them like this:
#product.prices.each do |price|
price.country.name
# now you already have the price
end
Of course, your countries will now potentially be in an unsatisfactory order, and for each price that you display you'll be triggering an additional DB query. With a large table of prices this could quickly become a performance issue.
The solution would be to either create a scope that you can use, or manually fetch your prices rather than just using the bare association, allowing you to eager-load your associated data and order your prices based on them:
# In your controller, or model code somewhere:
#prices = #product.prices.joins(:country).order('countries.name').includes(:country)
# The joins is required for ordering, and the includes ensures you eager-load that data
# In your view:
#prices.each do |price|
price.country.name # Now these should be in the correct order and eager-loaded rather than fetched in ever iteration of this prices loop
# you already have the price to use here
end

ActiveAdmin sort by attribute sum of associated objects

I have the following models in my Ruby on Rails application in which I'm using Postgres Database:
class Sale < ApplicationRecord
has_many :line_items
end
class LineItem < ApplicationRecord
belongs_to :sale
end
There are now 2 things I want to achieve:
First, I'd like to create an index page in ActiveAdmin for Sales, so I could, for each sale, display the sum of line items prices.
What I already tried, which doesn't work very well(it's very slow):
ActiveAdmin.register Sale do
actions :index
remove_filter :line_items
index do
column :created_at
column :price do |sale|
sale.line_items.sum(:price)
end
end
end
Second, I'd like to make this column sortable - would it be possible?
My suggestion for your case above you can just group based sale_id and then sum the price and to the sort with method below, reverse will get you descending order
LineItem.group(:sale_id).sum(:price).sort_by{|k, v| v}.reverse
if you need probably top ten you can use first(10)
LineItem.group(:sale_id).sum(:price).sort_by{|k, v| v}.reverse.first(10)
Try registering a database view that sums the prices. The documentation on custom sorting should still apply. Links to tips and tricks like this can be found on the wiki.

rails 4 HABTM relation and extra fields on join table

What I have (pseudo code):
model Document
column :title
HABTM :users
model User
column :name
HABTM :documents
Document has users (being approvers for document, either approve or not), and in this context join table should have extra column approved for each user.
jointable
user_id, document_id, approved
1 , 1 , true
2 , 1 , false
What I want is basically:
contract.approvers => returns users but with possibility to =>
contract.approvers.first.approve(:true) => and it updates JOINtable approve column to TRUE.
Answer right for this situation is optional, will appreciate advises on schema too (or maybe i should use other type of relation?).
HABTM has been deprecated a while ago, I think it is just a reference to has many through now.
Either way
join table name = DocumentReview
Document
has_many :document_reviews
has_many :users, through: :document_reviews
User
has_many :document_reviews
has_many :documents, through: :document_reviews
I don't understand how contract fits into this, i think you are saying that a document is a contract?
I would put the approve method in a separate class
class DocumentSignOff
def initialize(user, document)
#document_review = DocumentReview.find_by(user: user,document: document)
end
def approve!
#maybe more logic and such
#document_review.udpate(approved: true)
end
end
end

Updating product stock based on shopping cart quantity and updating cart items when product is changed

just a (hopefully) quick one today, apologies if it's super simple and I'm just thick.
I'm have a basic e-commerce app that I'm working on, and have 2 questions:
I'd create a :product in admin with an amount of stock. I'm looking to automatically update the stock of a :product if one or more is added to someone's cart as a :cart_item, based on the quantity that they've got in their cart (even before checkout). So one update if a product is added, and another update if a customer changes quantity from the cart view.
I'd like the name and price of :cart_item in a customers cart to be updated automatically if admin updates the associated :product.
Here are my model associations so far:
Customer
has_one :cart
has_many :orders
Product
has_many :cart_items
Cart
belongs_to:customer
has_many :cart_items
CartItem
belongs_to :product
belongs_to :cart
I only have scaffolds so far so all my current code is out of the box Rails 3.2.14.
I'm just not sure how to get the :cart_items to interact with the :products and vice versa. What code/extra functionality should I add to get this working? Thanks for the help.
Assuming that CartItem belongs_to :product (which seems likely), and has a quantity attribute that indicates the number in the cart:
1) I believe the functionality you want could be accomplished using callbacks on CartItem. For instance,
class CartItem < AR:B
after_save :remove_from_stock
after_destroy :return_to_stock
def remove_from_stock
product.stock -= self.quantity
product.save
end
def return_to_stock
product.stock += self.quantity
product.save
end
end
2) When you display the CartItem, just refer to it's associated product:
<% #cart_items.each do |cart_item| %>
Item Name: <%= cart_item.product.name %>
Item Price: <%= cart_item.product.price %>
<% end %>
This way, any change to the associated Product will be reflected in any view that refers to it.
If you're displaying many at once, make sure to use eager loading to avoid N+1 queries:
#cart_items = CartItem.includes(:product).where(<whatever>)

Resources