Search code examples
ruby-on-rails-3modelrelationshipbelongs-to

Link to new record with automatic belongs_to relationship?


In my Rails 3 application I have a simple model relationship which is as follows:

Animal Model

has_many :claims

Claim Model

belongs_to :animal
has_many :payments

Payments Model

belongs_to :claim

The claim table has a column called animal_id and the payments table has a column called claim_id.

I can successfully list all payments owned by a claim.

What I am trying to do is add a link within the animal show view that creates a new claim with the animal_id already set and the same with the claim show view for the new payment link.

From what I have read you can manually create a link_to with the controller and action set, like so:

Claim Show View

<%= link_to 'Create a Payment', {:controller => "payments", :action => "new", :claim_id => '@claim.id'} %>

This doesn't seem to work, although it does correctly link to the new payment page.

Is there a simpler way?


Solution

  • Off the top of my head, and untested, I think the following would work:

    = link_to 'Create Payment', payments_path(:payment=>{:claim_id=>@claim.id}), :method => :post
    

    Adding a hash inside the url helper is just going to put params on the url, which will be interpreted by rails the same way "normal" params posted from a form are.

    This will be equivalent to submitting a new payment form, so it will redirect the same way that would. If you want it to be handled via ajax just add :remote => true, and be sure your the create action on your PaymentsController responds to javascript correctly.


    Update: Read your question again, you want the new payment form with the claim_id already set?

    Ok, there are many ways you could do this. If you pass params to the new action you can take the claim_id from the params, the same as I showed above for creating a record:

    = link_to 'New Payment', new_payment_path(:claim_id=>@claim.id)
    

    This should link you to /payments/new?claim_id=123

    Then in your controller:

    def new
      @payment = Payment.new(:claim_id => params[:claim_id])
    end
    

    However, as was pointed out in the comments, the better way to do this is to nest payments under claims:

    In your routes:

    resources :claims do
      resources :payments
    end
    

    In your PaymentsController:

    before_filter :load_claim
    
    def new
      @payment = @claim.payments.build
    end
    
    def create
      @payment = @claim.payments.build(params[:payment])
      ...
    end
    
    private
    def load_claim
      @claim = Claim.find(params[:claim_id])
    end
    

    In your link:

    = link_to 'New Payment', new_claim_payment_path(@claim)
    

    Just be aware that now your payment path helpers will need claims in them, ie:

    = link_to 'Payment', claim_payment_path(@claim, payment)
    

    Same thing for form helpers:

    = form_for [@claim, @payment] ...