Reputation: 175
I am building a rails application that associates serial #'s with software titles. For instance, I have a software title, and need to be able to upload batches of serial #'s(codes) and associate it with that specific software title. It needs to be simple enough for a user(authenticated) to click an upload link, select a software title from a dropdown and hit import. Here is what I have so far... It does not necessarily have to be a csv it could be a text file too. I just need help figuring out the best way to accomplish this.
Code Schema
create_table "codes", force: :cascade do |t|
t.integer "software_id"
t.integer "user_id"
t.string "label"
t.string "code"
t.string "in_use"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "codes", ["software_id"], name: "index_codes_on_software_id"
add_index "codes", ["user_id"], name: "index_codes_on_user_id"
Code 'form' for UI
<%= simple_form_for(@code) do |f| %>
<%= f.error_notification %>
<div class="form-inputs">
<%= f.association :software %>
<%= f.input :label %>
<%= f.input :code %>
</div>
<div class="form-actions">
<%= f.file_field :code %>
<br>
<%= f.button :submit, "Upload Codes", class: 'btn btn-warning' %>
</div>
<br>
<% end %>
Code.rb Model
class Code < ActiveRecord::Base
belongs_to :software
belongs_to :user
accepts_nested_attributes_for :software
def self.import(file)
CSV.foreach(file.path, headers: true) do |row|
Code.create! row.to_hash
end
end
end
Software.rb Model
class Software < ActiveRecord::Base
has_many :software_assigns
has_many :products, through: :software_assigns
has_many :software_downloads
has_many :codes
end
Codes Controller
class CodesController < ApplicationController
before_action :authenticate_user!
before_action :verify_admin
before_action :set_code, only: [:show, :edit, :update, :destroy]
# GET /codes
# GET /codes.json
def index
@codes = Code.all
end
# GET /codes/1
# GET /codes/1.json
def show
end
# GET /codes/new
def new
@code = Code.new
end
# GET /codes/1/edit
def edit
end
# POST /codes
# POST /codes.json
def create
@code = Code.new(code_params)
respond_to do |format|
if @code.save
format.html { redirect_to @code, notice: 'Codes were successfully created.' }
else
format.html { render :new }
end
end
end
# PATCH/PUT /codes/1
# PATCH/PUT /codes/1.json
def update
respond_to do |format|
if @code.update(code_params)
format.html { redirect_to @code, notice: 'Codes were successfully updated.' }
else
format.html { render :edit }
end
end
end
# DELETE /codes/1
# DELETE /codes/1.json
def destroy
@code.destroy
respond_to do |format|
format.html { redirect_to codes_url, notice: 'Codes were successfully destroyed.' }
end
end
def import
Code.import(params[:file])
redirect_to codes_path, notice: 'Codes were successfully uploaded!'
end
private
# Use callbacks to share common setup or constraints between actions.
def set_code
@code = Code.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def code_params
params.require(:code).permit(:software_id, :label, :code)
end
end
Upvotes: 0
Views: 1275
Reputation: 882
Ok - doing a lot of communication in the comments and I think I can put together an answer now.
So, as per my edit to pitabas prathal's answer, you need to look for by the :code
key in the code_params hash, but since the Code class has no idea that you've got a code_params[:software_id]
to refer to, you'll need to pass that along. So your import method becomes:
code.rb
def self.import(file, software_id)
CSV.foreach(file.path, headers: true) do |row|
code = Code.new row.to_hash
code.software_id = software_id
code.save!
end
end
Then, your call to this method with the new argument, from the create
action (or your import
method on the controller):
Code.import(code_params[:code], code_params[:software_id])
Now, you are giving your Code class all the information it needs to associate the new Code
objects with the appropriate Software
object.
Edit
In your GoRails post, Chris Oliver's answer would also work, with one edit:
@software = Software.find(params[:software_id])
will not work - params[:software_id]
is nil. You can access software_id
from the code_params
hash:
@software = Software.find(code_params[:software_id])
or by adding the [:code] key in to the params reference like so:
@software = Software.find(params[:code][:software_id])
since [:software_id] is inside the [:code] array in the params
hash.
Upvotes: 1