Arminius
Arminius

Reputation: 606

Rails: how to use "returning id" (last inserted id in this code)

I have read about curval, lastval and the best one, returning id, but all the examples I have seen were written in plain sql (insert ...)

However, I am using active record here in my controller. The thing is I have a New Form to add articles with the File Upload field, but I also want to add pictures, which are in other table, so since the Pictures table has a Foreign Key pointing to Articles table, I need that last ID to do the insertion in my pictures table.

Here is the method in the Articles Controller

def create
      @article = current_user.articles.build(article_params)
    if @article.save
      flash[:success] = "Article created!"
      redirect_to root_url
    else
      render 'articles/new'
 end

Picture Model:

class Picture < ActiveRecord::Base
  belongs_to :article
 mount_uploader :picture, PictureUploader

end

And the Article Model has this

class Article < ActiveRecord::Base
  belongs_to :user
  has_many :pictures
  accepts_nested_attributes_for :pictures, allow_destroy: true

plus the validations

Update:

I have read that in this case, by writing Article.id you get the id of the last inserted row in the Articles table, yet, the second part of the question still remains, how do you use that to add it to the Save command to the Pictures table.

So, how do you go about that? simply writing "returning id below the line if @article.save ? (this is the kind of problems that arise when abandoning clear sql and having to write Active Record, I am lost with it. Then it is also unclear so far how to add that returning id to the Save method in the Pictures. UPDATE 2:

I am including the strong parameters

def article_params
      params.require(:article).permit(:country, :region, :town, :street, :company, :title, :content, :picture)
    end

The Top of the form

<%= form_for(@article, html: { multipart: true }) do |f| %>
  <%= render 'shared/error_messages', object: f.object %>

MY UPDATE:

The answer was still not correct as first there was a small bug in the fields_for in the Form which caused the picture not to be sent to the controller.

But once someone helped me with that, still there was a problem, which was that the picture simply would not get saved.

I looked in the Log and I could read: Unpermitted parameter picture. This was saying that the strong parameters private method was not correct when it came to the Pictures table. That is, this was not correct:

params.require(:article).permit(:country, :region, :town, :street, :company, :title, :content, :picture)

but the attribute picture had to be broken down in its parts like this:

def article_params
      params.require(:article).permit(:country, :region, :town, :street, :company, :title, :content, pictures_attributes: [:id, :article_id, :picture])
    end

And this finally solved it, but for someone who has been teaching Rails himself for two weeks, it was a challenge, despite having read most of the Guides and even the Hartl book. This was, to me, a bit advanced.

Upvotes: 0

Views: 1160

Answers (2)

Dharam Gollapudi
Dharam Gollapudi

Reputation: 6438

While creating the article, you don't need to manually assign the article_id to the picture object.

With all the models, associations in place and using the appropriate form helpers, you can let rails handle that for you.

Assuming you have a title field on the articles tables, you could use the following form, which when submitted, will setup both article and pictures for that article.

<%= form_for @article, html: { multipart: true } do |f| %>
  <%= f.text_field :title %>
  <%= fields_for :pictures do |ff| %>
    <%= ff.file_field :picture %>
  <% end %>
<% end %> 

You also need to setup/build these pictures in your new action of the ArticlesController as follows:

class ArticlesController < ApplicationController

  def new
    @article = current_user.articles.build
    @article.pictures.build
  end
end

And let rails know that you want to accept picture arguments from the article model as follows:

class Article < ActiveRecord::Base
  belongs_to :user
  has_many :pictures
  accepts_nested_attributes_for :pictures
end

Refer to FormHelpers#fields_for for more info.

Upvotes: 0

Chong Hui
Chong Hui

Reputation: 163

If you are adding pictures directly in the article form, you should build the pictures as so.

@article = current_user.articles.build(article_params)
@article.pictures.build

and in your models/article.rb add accepts_nested_attributes_for :pictures. so that you are able to add f.form_for :pictures do |ff| like so. Remember to add the attributes into the strong params as well.

Upvotes: 2

Related Questions