Рельсы 4: доступ к модели через другой

#ruby-on-rails #activerecord #ruby-on-rails-4 #actioncontroller

#ruby-on-rails #activerecord #ruby-on-rails-4 #actioncontroller

Вопрос:

У меня возникли проблемы с доступом к настройке модели изображения, например:

Запрос has_one has_many изображений галереи

Из представления show модели запроса мне нужно получить доступ к изображениям ее галереи, и это выдает мне ошибку undefined method 'pictures' for nil:NilClass .

Модели:

 class Request < ActiveRecord::Base
  belongs_to :user
  has_one :gallery
  has_many :pictures, through: :gallery
end

class Gallery < ActiveRecord::Base
  has_many :pictures, :dependent => :destroy
  belongs_to :request
end

class Picture < ActiveRecord::Base
  belongs_to :gallery
  has_attached_file :image,
    :path => ":rails_root/public/images/:id/:filename",
    :url  => "/images/:id/:filename"

  do_not_validate_attachment_file_type :image
end
  

Запрашивает контроллер:

 class RequestsController < ApplicationController
  before_action :set_request, only: [:show, :edit, :update, :destroy]

  def show
    @request  = Request.find(params[:id])
    @gallery = @request.gallery
    @pictures = @gallery.pictures
  end

  def new
    @request = Request.new
    @gallery = Gallery.new(params[:request_id])
    @gallery = @request.gallery
    @pictures = @gallery.pictures
  end

  def create
    @request = Request.new(request_params)

    respond_to do |format|
      if @request.save
        format.html { redirect_to @request, notice: 'Request was successfully created.' }
        format.json { render :show, status: :created, location: @request }
      else
        format.html { render :new }
        format.json { render json: @request.errors, status: :unprocessable_entity }
      end
    end
  end


  private
    # Use callbacks to share common setup or constraints between actions.
    def set_request
      @request = Request.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def request_params
        params.require(:request).permit(:title, :description, :username, gallery_attributes: [:id, :name, :description]).merge(user_id: current_user.id)
    end
end
  

Контроллер галерей:

 class GalleriesController < ApplicationController

  def show
    @gallery  = Gallery.find(params[:id])
    @pictures = @gallery.pictures

    respond_to do |format|
      format.html # show.html.erb
      format.json { render json: @gallery }
    end
  end

  def new
    @gallery = Gallery.new

    respond_to do |format|
      format.html # new.html.erb
      format.json { render json: @gallery }
    end
  end

  def create
    @gallery = Gallery.new(gallery_params)

    respond_to do |format|
      if @gallery.save

        if params[:images]
          params[:images].each { |image|
            @gallery.pictures.create(image: image)
          }
        end

        format.html { redirect_to @gallery, notice: 'Gallery was successfully created.' }
        format.json { render json: @gallery, status: :created, location: @gallery }
      else
        format.html { render action: "new" }
        format.json { render json: @gallery.errors, status: :unprocessable_entity }
      end
    end
  end

  def gallery_params
      params.require(:gallery).permit(:name, :description, :cover, :token)
  end
end
  

Контроллер изображений:

 class PicturesController < ApplicationController

  def show
    @picture = Picture.find(params[:id])

    respond_to do |format|
      format.html # show.html.erb
      format.json { render json: @picture }
    end
  end


  def new
    @gallery = Gallery.find(params[:gallery_id])
    @picture = @gallery.pictures.build

    respond_to do |format|
      format.html # new.html.erb
      format.json { render json: @picture }
    end
  end

  def create
    @picture = Picture.new(params[:picture])

    if @picture.save
      respond_to do |format|
        format.html {
          render :json => [@picture.to_jq_upload].to_json,
          :content_type => 'text/html',
          :layout => false
        }
        format.json {
          render :json => [@picture.to_jq_upload].to_json
        }
      end
    else
      render :json => [{:error => "custom_failure"}], :status => 304
    end
  end
  

Запрос показать вид: (сокращенный)

 <%- model_class = Request -%>
    <% unless @pictures.empty? %>
        <% @pictures.each do |pic| %>
            <li class="span3" id="picture_<%= pic.id %>">
              <div class="thumbnail">
                <%= image_tag pic.image.url %>
                <div class="caption">                       
                </div>
              </div>
            </li>
        <% end %>
    <% end %>
  

В представлении запроса я пытаюсь получить доступ к @pictures, который должен предоставить мне все изображения из галереи запроса. Я ненавижу публиковать так много кода, но я новичок в этом и не хочу ничего упускать. Есть идеи?

Комментарии:

1. Причина, по которой вы получаете эту ошибку, заключается в том, что @request.gallery возвращает null, что означает, что ваш request не gallery связан с ним.

2. Вы знаете, что я могу сделать, чтобы это исправить? Я думал, что мой контроллер запросов создавал его, когда я создавал запрос.

Ответ №1:

В этой части есть серьезные проблемы:

 def show
  @request  = Request.find(params[:id])
  @gallery = @request.gallery
  @pictures = @gallery.pictures
end

def new
  @request = Request.new
  @gallery = Gallery.new(params[:request_id])
  @gallery = @request.gallery
  @pictures = @gallery.pictures
end
  

В show вам нужно проверить, есть ли в запросе галерея или нет (если вы не добавляете проверку для ассоциации, вы можете сделать это следующим образом: validates_presence_of :gallery в Request модели). Другой способ — добавить нулевую проверку:

  def show
  @request  = Request.find(params[:id])
  unless @request.gallery.nil?
    @gallery = @request.gallery
    @pictures = @gallery.pictures
  end
end
  

Но если вы ожидаете, что это модели, добавьте ассоциацию:

 class Request < ActiveRecord::Base
  belongs_to :user
  has_one :gallery
  validates_presence_of :gallery
  has_many :pictures, through: :gallery
end
  

Также в новом действии просто создайте @request , с ним не связана галерея. Также вы определяете @gallery 2 раза, я не знаю причины. Вы могли бы ее построить:

 def new
  @request = Request.new
  @gallery = @request.build_gallery
  @pictures = @gallery.pictures
end
  

Я также не могу понять, что это params[:request_id] такое. Если это новое для запроса, какой идентификатор у вас уже есть?

Обновлено

Как я вижу, теперь вам нужно просто изменить new действие.

 def new
  @request = Request.new
end
  

Комментарии:

1. Спасибо за помощь. Я понимаю, что мой код в беспорядке, я просто экспериментировал, потому что не мог понять проблему. Что я должен был прояснить, так это то, что мне нужно, чтобы галерея создавалась при создании запроса, чтобы я мог использовать оба в одной форме. Вы знаете, как я мог бы это сделать?

2. Да, @request.build_gallery сделайте именно это, но вам нужно отправить ему некоторые параметры, и вы должны сделать это в create действии. Там будет только @request = Request.new request_params то, где request_params будут включены параметры галереи и автоматически назначены.

3. Еще раз спасибо, зише, наконец-то это работает. Ты меня хорошо научил. Счастливого пути.