25e782eb7e799e78d781b0026fc6a4d8

This is an attempt to make "complex forms" with has_many :through.
However I'm sure that there must be something better, this one feels dirty; also it doesn't trap exceptions for invalid records in the view.
There are better ways?

 Controller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
class Administration::ReportsController < Administration::HomeController

  # Rather than doing Document.find(params[:document_id]) in all the actions that need
  # to, just use a before filter.
  before_filter :find_document

  def new
    @report = @document.reports.build
    @report.reasons.build
  end

  def edit
    @report = @document.reports.find(params[:id])
  end

  def create
    @report = @document.reports.build(params[:report])

    if @report.save
      flash[:notice] = "Saved"
      redirect_to administration_document_report_url(@document, @report)
    else
      render :action => "new"
    end
  end

  def update
    @report = @document.reports.find(params[:id])

    if @report.update_attributes(params[:report])
      flash[:notice] = "Saved"
      redirect_to administration_document_report_url(@document, @report)
    else
      render :action => "new"
    end
  end
  private
  def find_document
    @document = Document.find(params[:document_id])
  end
end

Model

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class Report < ActiveRecord::Base

  belongs_to :document, :counter_cache => true

  has_many :report_reasons
  has_many :reasons, :through => :report_reasons #, :accessible => true

  validates_associated :reasons

  attr_accessor :new_reason_attributes
  attr_accessor :existing_reason_attributes

  after_save :build_reasons

  protected

  def build_reasons

      reasons.clear
      unless new_reason_attributes.blank?
        new_reason_attributes.each do |new_reason|
          reasons << Reason.find_or_create_by_content(new_reason["content"])
        end
      end
      unless existing_reason_attributes.blank?
        existing_reason_attributes.each do |existing_reason|
          reasons << Reason.find_or_create_by_content(existing_reason[1]["content"])
        end
      end

  end

end

 View reports/new.html.erb

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<% form_for [:administration, @document, @report] do |f| -%>

<dl class="form">

	<dt class="required"><%= t :when %> <%= f.error_message_on :when %> <span>(...)</span></dt>
	<dd><%= f.date_select :when, :include_blank => false, :start_year => Time.now.year - 20, :end_year => Time.now.year %></dd>

	<div id="reasons">
		<%= render :partial => 'reason', :collection => @report.reasons %>
	</div>
	<p><%= add_reason_link "Add a reason" %></p>

</dl>

<%= f.submit %>
<% end -%>

View reports/_reason.html.erb

1
2
3
4
5
6
7
8
<div class="reason">
	<% new_or_existing = reason.new_record? ? 'new' : 'existing' %>
	<% prefix = "report[#{new_or_existing}_reason_attributes][]" %> 
	<% fields_for prefix, reason do |reason_form| -%>
		<dt class="required">Reason <%= reason_form.error_message_on :content %></dt>
		<dd><%= reason_form.text_field :content %> <%= link_to_function "remove", "$(this).up('.reason').remove()" %></dd>
	<% end -%>
</div>

Refactorings

No refactoring yet !

Your refactoring





Format Copy from initial code

or Cancel