Devin
Devin

Reputation: 1021

Saving to another Model database, with current Form record ID - Rails

I'm trying to get the text from a text_area field in a form to save to a database in a different Model with the current Model's ID.

Currently, this works but only will save integers. If I put text into the 'Notes' field, then its saves it as a '0'. I suspect this is working correctly but I'm missing a piece to my puzzle. This is because I only want the 'Ticket' to save the note_id because I will have multiple 'Notes' per 'Ticket.

How can I get the Note to save in the Note Model, with an ID, and associate that note_id with this specific ticket?

Form - /app/views/tickets/_form.html.erb

<%= form_for(@ticket) do |f| %>
<% if @ticket.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@ticket.errors.count, "error") %> prohibited this ticket from being saved:</h2>
<ul>
<% @ticket.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>

<div class="field">
  <%= f.fields_for :notes do |u|%>
  <%= u.label :note %>
  <%= u.text_area :note, :size => "101x4", :placeholder => "Leave notes here." %>
<% end %>
</div>

<div class="actions">
   <%= f.submit %>
</div>
<% end %>

Tickets_controller.rb

class TicketsController < ApplicationController
# GET /tickets
# GET /tickets.json
def index
@tickets = Ticket.all

respond_to do |format|
  format.html # index.html.erb
  format.json { render json: @tickets }
end
end

# GET /tickets/1
# GET /tickets/1.json
def show
@ticket = Ticket.find(params[:id])

respond_to do |format|
  format.html # show.html.erb
  format.json { render json: @ticket }
end
end

# GET /tickets/new
# GET /tickets/new.json
def new
@ticket = Ticket.new
@ticket.notes.build

respond_to do |format|
  format.html # new.html.erb
  format.json { render json: @ticket }
end
end

# GET /tickets/1/edit
def edit
@ticket = Ticket.find(params[:id])
end

# POST /tickets
# POST /tickets.json
def create
@ticket = Ticket.new(params[:ticket])

respond_to do |format|
  if @ticket.save
    format.html { redirect_to @ticket, notice: 'Ticket was successfully created.' }
    format.json { render json: @ticket, status: :created, location: @ticket }
  else
    format.html { render action: "new" }
    format.json { render json: @ticket.errors, status: :unprocessable_entity }
  end
end
end

# PUT /tickets/1
# PUT /tickets/1.json
def update
@ticket = Ticket.find(params[:id])

respond_to do |format|
  if @ticket.update_attributes(params[:ticket])
    format.html { redirect_to @ticket, notice: 'Ticket was successfully updated.' }
    format.json { head :no_content }
  else
    format.html { render action: "edit" }
    format.json { render json: @ticket.errors, status: :unprocessable_entity }
  end
end
end

# DELETE /tickets/1
# DELETE /tickets/1.json
def destroy
@ticket = Ticket.find(params[:id])
@ticket.destroy

respond_to do |format|
  format.html { redirect_to tickets_url }
  format.json { head :no_content }
end
end
end

Note.rb

class Note < ActiveRecord::Base
belongs_to :ticket
attr_accessible :note, :ticket_id
end

Ticket.rb

class Ticket < ActiveRecord::Base
attr_accessible :notes_attributes
accepts_nested_attributes_for :notes
end

Upvotes: 1

Views: 1019

Answers (2)

Rahul Tapali
Rahul Tapali

Reputation: 10137

It is because note_id is an integer type.

Use nested models: Refer this for Nested Models

Model:

class Ticket < ActiveRecord::Base
  has_many :notes
  attr_accessible :note_id, :notes_attributes
  accepts_nested_attributes_for :notes
end

View:

<%= form_for(@ticket) do |f| %>
    <%= f.fields_for :notes do |u|%>
      <%= u.label :note %>
      <%= u.text_area :note %>
    <% end %>
    <%= f.submit 'Submit' %>
<% end %>

Upvotes: 4

Paul Richter
Paul Richter

Reputation: 11072

What you have is a nested association, with Ticket as the "parent". The association is governed by the link from note_id in the Note model to the id (primary key) of the Ticket. What you're presently doing right now is manually manipulating that numeric association. Rails, knowing that the note_id column is supposed to be an integer, is taking the text you're trying to insert and turning it in to a number (zero in this case). You've probably got a bunch of orphaned rows right now because of this.

Ultimately, in order to accomplish what you're trying to do, your form will need to provide fields for that associated model. One way you can handle this is by using the accepts_nested_attributes_for in your Ticket model. Like so:

class Ticket < ActiveRecord::Base
    has_many :notes
    accepts_nested_attributes_for :notes
end

And in your form, you can easily create a nested form like so:

<%= form_for(@ticket) do |f| %>
   <div class="field">
        <%= f.fields_for :notes do |f_notes|%>
            <%= f_notes.label :note %><br />
            <%= f_notes.text_area :note, :size => "101x4", :placeholder => "Please leave notes here."%>
        <% end %>
    </div>
<% end %>

Edit Almost forgot: Check out this Railscast from Ryan Bates dealing with Nested Attributes

Edit 2 As codeit pointed out, you don't need the attr_accessible :note_id in Ticket. Since you've indicated that a Ticket has many Notes, and that Note belongs to Ticket, the foreign key column will appear in the Note model as ticket_id, which you already have. Having note_id in the ticket model is useless, and also nonsensical since has_many describes a plural relationship (which can't be expressed with a single column).

Upvotes: 2

Related Questions