1

I am new to Rails and struggling to get a formtastic form to save - the database keeps rolling back the insertion without any apparent explanation.

I have a PublishedItem and a Citation. Each PublishedItem can have many references to other PublishedItems via Citation - here is the (stripped down) PublishedItem model:

    class PublishedItem < ActiveRecord::Base

      attr_accessible :date_published, 
              :author_ids,
              :cited_published_item_ids,
              :citing_published_item_ids

      has_many :authorships
      has_many :authors, through: :authorships, order: "last_name, first_name"

      has_many :citations, 
        foreign_key: "citing_published_item_id", 
        class_name: "Citation", 
        dependent: :destroy

      has_many :cited_published_items, 
        through: :citations, 
        source: :cited

      has_many :reverse_citations, 
        foreign_key: "cited_published_item_id", 
        class_name: "Citation", 
        dependent: :destroy

      has_many :citing_published_items, 
        through: :reverse_citations, 
        source: :citing

There are other relationships, but I have only included one for comparison purposes: The Authorship relationship, a more typical relationship to another table, Authors save properly. It is just the self-referencing one where I am having a problem.

Here is the Citations Model:

    class Citation < ActiveRecord::Base

      attr_accessible :citation_type, :cited_id, :citing_id

      belongs_to :citing, 
        class_name: "PublishedItem", 
        foreign_key: "citing_published_item_id"

      belongs_to :cited, 
        class_name: "PublishedItem", 
        foreign_key: "cited_published_item_id"

And the table (postgresql):

    CREATE TABLE citations
    (
      id serial NOT NULL,
      citing_published_item_id integer,
      cited_published_item_id integer,
      citation_type character varying(255),
      created_at timestamp without time zone NOT NULL,
      updated_at timestamp without time zone NOT NULL,
      CONSTRAINT published_item_citations_pkey PRIMARY KEY (id )
    )
    WITH (
      OIDS=FALSE
    );

The new.html.erb form (extract):

    <%= semantic_form_for @published_item do |f| %>
      <%= f.semantic_errors %>
      <%= f.inputs do %>
        <%= f.input :title %>
        <%= f.input :authors, as: :select, 
           collection: Author.find(:all, order: "last_name ASC, first_name ASC") %>
        <%= f.input :cited_published_items, as: :select, 
           collection: PublishedItem.find(:all, order: "title ASC") %>
      <% end %>
      <%= f.actions do %>
        <%= f.action :submit, button_html: { class: "btn btn-primary" } %>
        <%= f.action :cancel, button_html: { class: "btn btn-default" } %>
      <% end %>

What I would like to have happen, and cannot seem to achieve, is to reference another PublishedItem being passed into the new PublishedItem form, and insert a record into Citations with the original PublishedItem as cited_published_item, and the new PublishedItem as the citing_published_item. But I am stumped. Whenever I select a PublishedItem in the select list, the query rollsback. Authorship (and other M:M) work properly.

Any help greatly appreciated.

Alan
  • 1,298
  • 2
  • 17
  • 20
  • see http://stackoverflow.com/questions/2182428/rails-nested-form-with-has-many-through-how-to-edit-attributes-of-join-model – m_x Dec 08 '12 at 12:13
  • thanks @m_x, but it doesn't really help me - I cannot see how to reference the other side of the relationship when it is the same object. I have tried every combination of `@published_item.xxx.build.build_yyy` and none of them works. I added ` ... ` and cannot get any joy there either. I am almost at the point where I am going to separate it out into two tables for the cited and the citing published items, which would be a shame. – Alan Dec 08 '12 at 22:56

1 Answers1

1

try something like this -

controller :

def new
  @published_item = PublishedItem.new
  @published_item.citations.build
end

PublishedItem model :

accepts_nested_attributes_for :citations
# i noticed your accessible foreign keys were set wrong here
attr_accessible :citation_type, 
                :cited_published_item_id, 
                :citing_published_item_id

form :

<%= semantic_form_for @published_item do |form| %>
  # published_item fields
  <%= form.fields_for :citations do |citation_subform| %>
    <%= citation_subform.select :cited_published_item_id,
          options_for_select( 
            PublishedItem.order(:title).map{|p|[p.title,p.id]} 
          ) %>
  <% end %>
<% end %>

you want your form to pass params structured like this :

{published_item : 
  {citations_attributes: 
    [
      {cited_published_item_id: xxx}
    ]
  }
}
m_x
  • 11,705
  • 6
  • 43
  • 57
  • Thank you @m_x - I have solved it now, thanks to you. There were a couple of other problems in my code, but now it is just cosmetics. Thank you so much!! When I have 15 reputation points, I will upvote your answer, for now I don't have the permission. Thanks again. I have learned a lot from your example. – Alan Dec 10 '12 at 06:07
  • Here is a follow up question: with validates presence of citing_published_item_id, the form reports an error that citations citing cannot be blank. But without the validation, the data posts correctly, including the correct value for citing... Can this be explained? – Alan Dec 10 '12 at 10:56
  • mmm... this is weird. I guess it's because the Citation is saved _after_ the published item (see the doc on nested attributes), but the validation process must occur _before_ any of the two is saved. You should open another question on this, because this is the policy on SO - one problem, one question. – m_x Dec 11 '12 at 09:01
  • a bit late, for an upvote, but there you go. Apologies I forgot to come back and fulfil my promise to upvote when I had the reputation. – Alan Mar 30 '18 at 03:32