How to return object from db but still needing to render errors, rails

时间:2018-02-03 09:47:04

标签: ruby-on-rails ruby

I have a Micropost model and a Gallery model and a Picture model and the pictures either belong to Micropost or Gallery model. I have a micropost form where it accepts_nested_attributes_for :pictures and have set the associations in models, and, controller micropost create action and strong parameters look like this,

Micropost_controller

def create
  @micropost = current_user.microposts.create(micropost_params)
  @pictures = @micropost.pictures
  @pictures.each do |pic|
    pic.update!(gallery_id: params[:gallery_id])
  end   
  ...
  render 'static_pages/home'
end

def micropost_params
  params.require(:micropost).permit(:content, pictures_attributes: [:id, :gal_refs_id, :picture, :_destroy]))
end

The gallery is preset so I have its id which is sent in a hidden field and retrieved in the microposts controller as shown.

Problem is I need to return the @micropost object so I can update the :gallery_id, so I cannot use @micropost.save as it only returns true or false and this is the behavior I need to re-render the form if errors occur.

At the moment using create it silently fails and renders the template.

How can I overcome this or is there a better way to do this?

Thanks in advance!

2 个答案:

答案 0 :(得分:2)

Try using the below code. If @micropost has no errors, it will create @micropost and you can update its associated objects

def create
  @micropost = current_user.microposts.build(micropost_params)
  if @micropost.save
    # if the object has no errors
    @pictures = @micropost.pictures
    @pictures.each do |pic|
      pic.update!(gallery_id: params[:gallery_id])
    end   
    ...
    render 'static_pages/home'
  else
    # show Errors
    @micropost.errors
  end
end

def micropost_params
  params.require(:micropost).permit(:content, pictures_attributes: [:id, :gal_refs_id, :picture, :_destroy]))
end

答案 1 :(得分:1)

Models:

class Micropost
  has_many :pictures, as: :imageable, inverse_of: :imageable
end

class Picture
  belongs_to :imageable, polymorphic: true
end

class Gallery
  has_many :pictures, as: :imageable, inverse_of: :imageable
end

# Note: inverse_of is important here! It allows you to instantiate the
#       Picture object without having a Picture object yet.

Controller:

def create
  @micropost = micropost.new(micropost_params)

  @pictures.each do |picture|
    @micropost.pictures.new({
      picture: picture,
      gallery_id: params[:gallery_id]
    })
  end

  # Note: Pictures will not be saved or persisted in the database until
  #       .save is called.
  # Note: If your Picture object is invalid, Micropost save will also fail

  if @micropost.save
    # Saved, do something here with the success response
    render 'static_pages/home'
  else
    # Errors
    @micropost.errors
  end
end

Picture Validation: This is code from my production app, adjust to your needs.

    steam_game_details['images'].each do |image|
      image_file_name = image.split('/').last.split('?').first

      local_picture = picture.where({
        picture_file_name: image_file_name
      }).first_or_initialize

      # Check if the image is nil and whether or not it actually exists on AWS S3
      # 
      if local_picture.picture.nil? || !local_picture.picture.exists?
        local_picture.assign_attributes({
          picture: open(URI.parse(image)),
          picture_file_name: image_file_name # Overwrite the name generated by Paperclip
        })
      end
    end