Rails associations in a form - ruby-on-rails

I am trying to figure out how to register certain values to their respective table using the form, check the order form to better understand which values need to be registering to which table.
I have also displayed the table entries, models and controller related to this question. If someone can guide me to where I can obtain further understanding on coding the associations in forms that would be great.
order form
<%= simple_form_for(#order) do |f| %>
<%= f.association :items, collection: Item.all, label_method: :name, value_method: :id %>
<%= [need to display the price of the item selected] %>
<%= f.input :quantity ???? [need to register in the order_items table] %>
<%= [register sub total to orders table] %>
<%= f.submit %>
<% end %>
tables
create_table "order_items", force: true do |t|
t.integer "item_id"
t.integer "order_id"
t.integer "quantity"
end
create_table "orders", force: true do |t|
t.integer "user_id"
t.integer "client_id"
t.boolean "status"
t.decimal "sub_total"
end
create_table "items", force: true do |t|
t.string "name"
t.decimal "price"
t.integer "stock"
end
models
class Order < ActiveRecord::Base
...
has_many :order_items
has_many :items, :through => :order_items
end
class Item < ActiveRecord::Base
...
has_many :order_items
has_many :orders, :through => :order_items
end
class OrderItem < ActiveRecord::Base
belongs_to :item
belongs_to :order
end
orders controller
def create
#order = Order.new(order_params)
#order.user_id = current_user.id
#order.status = TRUE
end
def order_params
params.require(:order).permit(:code, :client_id, :user_id, :memo, :status, item_ids: [])
end

Related

Unpermitted parameters In Rails 5 Project

I've spent a few hours trying to solve this problem in a Rails 5 project that I have. The issue is that I keep getting:
Unpermitted parameters: :item_instance_ids, :note_ids
when I submit a form. I believe that the relationships between the models are wrong. I'm using a polymorphic relationship which is the first time I've used it. I've looked through so many posts on StackOverFlow as well as guides on the web but nothing seems to help me.
Basically, I have an incoming purchases form - like an ordering form and within that form you should be able to add multiple items, like a laptop, keyboard, monitor, to the order => the item instances model.
Anyways, here is my code:
incoming_purchases.rb:
class IncomingPurchase < ApplicationRecord
# Relations
has_many :item_instance, :as => :instance_wrapper
has_many :notes, :as => :notable
belongs_to :user
end
item_instance.rb
class ItemInstance < ApplicationRecord
# Relations
belongs_to :instance_wrapper, polymorphic: true
belongs_to :item
belongs_to :user
has_many :notes, :as => :notable
end
views/incoming_purchases/_form.html.erb:
<%= simple_form_for(#incoming_purchase) do |f| %>
<%= f.error_notification %>
<%= f.error_notification message: f.object.errors[:base].to_sentence if f.object.errors[:base].present? %>
<div class="form-inputs">
<%= f.association :item_instance, as: :check_boxes, :label_method => lambda { |item_instance| "#{item_instance.item.description}" } %>
<%= f.label(:date_ordered, "Order Date:") %>
<%= f.text_field(:date_ordered, class: 'form-control-date') %>
<%= f.association :user, :label_method => lambda { |user| "#{user.username}" } %>
<%= f.input :order_number %>
<%= f.input :vendor %>
<%= f.input :po_number %>
<%= f.input :tax %>
<%= f.input :shipping %>
<%= f.association :notes %>
</div>
<div class="form-actions">
<%= f.button :submit, class: "btn btn-outline-success" %>
</div>
<% end %>
incoming_puchases_controller.rb:
class IncomingPurchasesController < ApplicationController
before_action :set_incoming_purchase, only: [:show, :edit, :update, :destroy]
def new
#incoming_purchase = IncomingPurchase.new
end
def create
puts '*********************'
puts params
puts '*********************'
puts incoming_purchase_params
puts '**********************'
#incoming_purchase = IncomingPurchase.new(incoming_purchase_params)
respond_to do |format|
if #incoming_purchase.save
format.html { redirect_to #incoming_purchase, notice: 'Incoming purchase was successfully created.' }
format.json { render :show, status: :created, location: #incoming_purchase }
else
format.html { render :new }
format.json { render json: #incoming_purchase.errors, status: :unprocessable_entity }
end
end
end
private
def set_incoming_purchase
#incoming_purchase = IncomingPurchase.find(params[:id])
end
def incoming_purchase_params
params.require(:incoming_purchase).permit(:item_instances_id, :date_ordered, :user_id, :order_number, :vendor, :po_number, :tax, :shipping, :notes_id)
end
end
schema.rb:
ActiveRecord::Schema.define(version: 2020_08_31_200026) do
create_table "incoming_purchases", options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
t.bigint "item_instances_id"
t.date "date_ordered"
t.bigint "user_id"
t.string "order_number"
t.string "vendor"
t.integer "po_number"
t.decimal "tax", precision: 8, scale: 2
t.decimal "shipping", precision: 8, scale: 2
t.bigint "notes_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["item_instances_id"], name: "index_incoming_purchases_on_item_instances_id"
t.index ["notes_id"], name: "index_incoming_purchases_on_notes_id"
t.index ["user_id"], name: "index_incoming_purchases_on_user_id"
end
create_table "item_instances", options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
t.integer "inv_number"
t.string "serial"
t.integer "po_number"
t.date "po_date"
t.date "invoice"
t.date "date_out"
t.decimal "cost", precision: 8, scale: 2
t.string "acro"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.bigint "item_id"
t.index ["item_id"], name: "fk_rails_6ea33fd9d0"
end
add_foreign_key "incoming_purchases", "item_instances", column: "item_instances_id"
end
Oh, on the controller I tried:
params.require(:incoming_purchase).permit({ :item_instance_ids => [] }, :date_ordered, :user_id, :order_number, :vendor, :po_number, :tax, :shipping, :notes_id)
Again, I think the problem is how the relationship is set up between these two models. Thank you for any help.
I tried changing my permit params to the following:
params.require(:incoming_purchase).permit(:item_instances_id, :date_ordered, :user_id, :order_number, :vendor, :po_number, :tax, :shipping, notes_id: [], item_instances_id: [])
I was able to add an item but of course item_instances_id did not go through. When the params comes through it looks like this:
{"utf8"=>"✓", "authenticity_token"=>"d3jF73WyKCs69RSCFDvQlh7RyUAg0GQk8m7GKHX6/tt+Ve/1Y1oE5P1UtIMJfCIYS+YL0DwZth9UlDcnyW1uiA==", "incoming_purchase"=>{"item_instance_ids"=>["", "31"], "date_ordered"=>"2020-09-01", "user_id"=>"2", "order_number"=>"1", "vendor"=>"1", "po_number"=>"1", "tax"=>"1", "shipping"=>"1", "note_ids"=>[""]}, "commit"=>"Create Incoming purchase", "controller"=>"incoming_purchases", "action"=>"create"}
notice the item_instance_ids however, on the incoming_purchases model it's
item_instances_id notice the position of that s on ids and instances.
It looks like the filters you are passing into permit are not correct.
It probably needs to be note_ids: [] as this is a has_many relationship.
And when passing nested parameters into permit they should be placed at the end. So, you also have to move item_instance_ids to the end, either before or after note_ids: [].
Edit
You might be better off with a has_many :though relationship for tying items to a purchase. I'm not sure how your Item model looks like so I kept it simple.
incoming_purchase.rb
class IncomingPurchase < ApplicationRecord
has_many :purchase_items
has_many :items, through: :purchase_items
end
purchase_item.rb
class PurchaseItem < ApplicationRecord
belongs_to :incoming_purchase
belongs_to :item
end
item.rb
class Item < ApplicationRecord
has_many :purchase_items
has_many :incoming_purchases, through: :purchase_items
end

How to manage nested relation in RoR?

I'm new to Rails and trying to create an C2C marketplace App just to understand how rails works and start some real project later on.
The idea is that User can place Order to other User. Orders is related with user's Printer (you choice user where you want to print on /order page). Printer in its turn have many colors to print
For now, Im stack with very basic things.
I want to display list of all printers with owner's name and colors available on /order page in Orders controller. Thank you in advance for any ideas how I can do this
class User < ActiveRecord::Base
has_many :printers, dependent: :destroy
has_many :orders, dependent: :destroy
end
class Order < ActiveRecord::Base
belongs_to :user
validates :user_id, presence: true
end
class Printer < ActiveRecord::Base
belongs_to :user
validates :user_id, presence: true
validates :model, presence: true, allow_nil: true
has_many :materials, dependent: :destroy
end
Orders controller with index action (/orders)
class OrdersController < ApplicationController
def index
#printers = Printer.all
end
end
And index.html.erb
<% #printers.each do |p| %>
<div class="col-xs-9">
<div><%= "USERNAME HERE" %></div> <!--Do not know how to display parent's model here? -->
<div><%= p.model %></div> <!--Works fine-->
<div><%= p.colors.each do |c| c.color end %></div> <!--Display array instead of strings-->
</div>
<div class="col-xs-3">
<button>Order</button>
</div>
<% end %>
Simplified schema.db
ActiveRecord::Schema.define(version: 20160627132435) do
create_table "colors", force: :cascade do |t|
t.string "color"
t.integer "printer_id"
end
create_table "orders", force: :cascade do |t|
t.string "price"
t.string "status"
t.integer "user_id"
end
create_table "printers", force: :cascade do |t|
t.string "model"
t.integer "user_id"
end
add_index "printers", ["user_id"], name: "index_printers_on_user_id", using: :btree
create_table "users", force: :cascade do |t|
t.string "first_name"
t.string "last_name"
end
add_foreign_key "orders", "users"
add_foreign_key "printers", "users"
end
I think you should be able to do:
<% #printers.each do |p| %>
<div class="col-xs-9">
<div><%= p.user.first_name %></div> <!--Do not know how to display parent's model here? -->
<div><%= p.model %></div> <!--Works fine-->
<div><% p.colors.each do |c|
<%= c.color %>
<% end %></div> <!--Display array instead of strings-->
</div>
<div class="col-xs-3">
<button>Order</button>
</div>
<% end %>

Adding Association to Join Table for HaBtM Relationship

I currently have 3 models (user, pairing, meetings), and the join table meetings_pairings.
User.rb
class User < ActiveRecord::Base
enum role: [:student, :supervisor, :admin]
has_many :students, class_name: "User",
foreign_key: "supervisor_id"
belongs_to :supervisor, class_name: "User"
has_and_belongs_to_many :pairings
end
Pairings.rb
class Pairing < ActiveRecord::Base
has_and_belongs_to_many :supervisor, class_name: 'User'
belongs_to :student, class_name: 'User'
has_and_belongs_to_many :meetings, join_table: :meetings_pairings
end
Meetings.rb
class Meeting < ActiveRecord::Base
enum status: [:available, :unavailable]
has_and_belongs_to_many :pairings, join_table: :meetings_pairings
end
Schema.rb (relevant bits)
create_table "meetings", force: :cascade do |t|
t.date "meeting_date"
t.datetime "meeting_time"
t.integer "status", default: 0, null: false
t.boolean "accepted"
end
create_table "meetings_pairings", id: false, force: :cascade do |t|
t.integer "pairing_id"
t.integer "meeting_id"
end
add_index "meetings_pairings", ["meeting_id"], name: "index_meetings_pairings_on_meeting_id"
add_index "meetings_pairings", ["pairing_id"], name: "index_meetings_pairings_on_pairing_id"
create_table "pairings", force: :cascade do |t|
t.integer "supervisor_id"
t.integer "student_id"
t.string "project_title"
end
add_index "pairings", ["student_id"], name: "index_pairings_on_student_id", unique: true
add_index "pairings", ["supervisor_id"], name: "index_pairings_on_supervisor_id"
I created the view and controller to enable a user (supervisor, which is in a pairing) to create a meeting. However I don't know how to add this association to the join table.
meetings_controller.rb
class MeetingsController < ApplicationController
def index
#meetings = Meeting.all
end
def new
#meeting = Meeting.new
end
def create
#meeting = Meeting.new(meeting_params)
if #meeting.save
redirect_to meetings_path, :notice => "Meeting Created!"
else
redirect_to meetings_path, :notice => "Meeting Failed!"
end
end
def show
#meeting = Meeting.find(params[:id])
end
private
def meeting_params
params.require(:meeting).permit(:meeting_date, :meeting_time)
end
end
Form from the view
<%= form_for #meeting do |f| %>
<div class="field">
<%= f.label :meeting_date %><br />
<%= f.text_field :meeting_date %>
</div>
<div class="field">
<%= f.label :meeting_time %><br />
<%= f.time_select :meeting_time, :ampm => true, :minute_step => 30, :default => {:hour => '9', :minute => '0'} %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
This creates an entry in the meetings table, so my question is how can I make it so that an entry is made into the join table with the pairing id of the current user who created the meeting ?
Decided to use a has_many :through (user-meeting-user) relationship instead. Question no longer relevant.

Show images on mypages

I am now trying to show the images, which a user already registered, on his or her 'mypage'.
Then, I wrote some codes as below.But it doesn't work.Could you give me some advises?
☆members_controller
#member= Member.find(params[:id])
#member.groups.reverse.map do |group|
#join_groups_images = group.imageurl
☆(members)show.html.erb
<div class="join_groups_images">
<%= image_tag #join_groups_images, :width => '20px' ,:height => '25px' %>
</div>
☆(model)member.rb
class Member < ActiveRecord::Base
attr_accessible :admin, :mail, :memo, :name, :pass, :user, :pass_confirmation
has_many :group_in_members, :dependent => :destroy
has_many :groups, :through => :group_in_members
☆(model)group_in_member.rb
class GroupInMember < ActiveRecord::Base
attr_accessible :group_id, :member_id
belongs_to :group
belongs_to :member
end
☆schema.rb
create_table "groups", :force => true do |t|
t.string "name"
t.text "memo"
t.boolean "admin"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.string "imageurl"
end
You didn't provide whole code from action in members controller, but I assume, that you are using .map{|| } in wrong way. You need a variable with array or even method in Member model.
class Member < ActiveRecord::Base
...
def images
groups.reverse.map(&:imageurl)
end
...
end
and then, put this in your view
<ul class="join_groups_images">
<% #member.images.each do |image| >
<li><%= image_tag image %></li>
<% end>
</div>
that should do the trick.

association id not getting set using accepts_nested_attributes_for and decent_exposure

When I post a form to create a new inquiry with a child comment (in the app, inquiries can have multiple comments), the comment is not getting built. It works when remove the presence validations. So it has to do with the order in which things are built and saved. How to preserve the validations and keep the code clean?
(The following is an example so it may not be exactly runable)
models/inquiry.rb
class Inquiry < ActiveRecord::Base
has_many :comments
accepts_nested_attributes_for :comments
models/comment.rb
class Comment < ActiveRecord::Base
belongs_to :inquiry
belongs_to :user
validates_presence_of :user_id, :inquiry_id
controllers/inquiry_controller.rb
expose(:inquiries)
expose(:inquiry)
def new
inquiry.comments.build :user => current_user
end
def create
# inquiry.save => false
# inquiry.valid? => false
# inquiry.errors => {:"comments.inquiry_id"=>["can't be blank"]}
end
views/inquiries/new.html.haml
= simple_form_for inquiry do |f|
= f.simple_fields_for :comments do |c|
= c.hidden_field :user_id
= c.input :body, :label => 'Comment'
= f.button :submit
database schema
create_table "inquiries", :force => true do |t|
t.string "state"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "comments", :force => true do |t|
t.integer "inquiry_id"
t.integer "user_id"
t.text "body"
t.datetime "created_at"
t.datetime "updated_at"
end
Basically, before saving you are also testing the presence of inquiry_id, the return association from comment to inquiry, that cannot be set until the comment is saved. An alternate way to achieve this and still have your validations intact would be the following:
comment = Comment.new({:user => current_user, :body => params[:body]
comment.inquiry = inquiry
comment.save!
inquiry.comments << comment
inquiry.save!
Or an alternate way would be
= simple_form_for inquiry do |f|
= f.simple_fields_for :comments do |c|
= c.hidden_field :user_id
= c.hidden_field :inquiry_id, inquiry.id
= c.input :body, :label => 'Comment'
= f.button :submit
Basically adding the following line in your comments form
= c.hidden_field :inquiry_id, inquiry.id

Resources