Rails - Как получить первую запись связанной таблицы? - PullRequest
1 голос
/ 16 апреля 2020

Я пытаюсь создать API для моего мобильного приложения.

У меня есть posts и images таблицы. Для моего API, я могу отправить все posts с:

@posts = Post.all render json: @posts

Output: [{"id":20,"title":"Title 1", "body":" first post ", "user_id":1 }]

Но он не содержит изображений вообще. Чтобы показать изображение витрины на домашней странице моего приложения, мне просто нужно первое изображение связанных изображений.

Мне нужен вывод (имя атрибута showcase_image не имеет значения):

Output: [{"id":20, "title":"Title 1", "body":" first post ", "showcase_image": 'first_image.jpg' , "user_id":1 }]

Мне нужно включить первое изображение из таблицы связанных изображений в мой json ответ ..

Заранее спасибо!

Ответы [ 2 ]

3 голосов
/ 17 апреля 2020

Я бы предложил использовать сериализатор. Сериализатор активной модели довольно стандартный и простой в использовании, но не получает никаких обновлений и имеет плохую производительность. Вы можете выбрать любой другой сериализатор (я рекомендую Blueprinter ) или использовать AMS. Через AMS вы можете определить отношение, которое хотите сериализовать, и оно будет строить json, которого вы ожидаете

class PostSerializer < ActiveModel::Serializer
  attributes :id, :title, :body, :showcase_image, :user_id

  def showcase_image
    object.images.first.name # don't know what is the attribute you're looking for
  end
end

И на вашем контроллере:

@posts = Post.includes(:images).all # Use includes to avoid N+1 problems
render json: @posts, serialize_collection: PostSerializer
0 голосов
/ 17 апреля 2020

Вы можете включить ассоциации с опцией :include при вызове as_json.

render json: @posts.as_json(include: :images)

Вы можете ограничить это одним изображением, добавив новую ассоциацию к Post .

class Post < ApplicationRecord
  has_many :images
  has_one :showcase_image, class_name: 'Image'
end

Это позволит вам вместо этого использовать :showcase_image.

render json: @posts.as_json(include: :showcase_image)

Вы также можете использовать Jbuilder для решения проблемы в hand без добавления дополнительной ассоциации.

# app/views/posts/index.json.jbuilder

# Get images that belong to posts, group them by post_id and
# return the minimum image id for each post_id.
images = Images.where(post_id: @posts.select(:id)).group(:post_id).minimum(:id)
# Request the full image data for all image ids returned above.
images = images.keys.zip(Image.find(images.values)).to_h

json.array! @posts do |post|
  json.extract! post, :id, :title, :body, :...

  json.showcase_image do
    image = images[post.id]
    if image
      json.extract! image, :id, :name, :location, :...
    else
      json.null!
    end
  end
end

Без вызова специфицированного рендера c Rails по умолчанию будет использовать файл app/views/posts/index и выберет файл, соответствующий запросу. (Если вы запрашиваете HTML, он ищет файл HTML, если вы запрашиваете JSON, он ищет JSON, et c.)

# app/controllers/posts_controller.rb
class PostsController < ApplicationController
  def index
    @posts = Post.all
  end
end

Теперь, когда вы запрашиваете /posts.json или /posts с заголовком Accept: application/json ваше приложение должно вернуть сборку ответа JSON от Jbuilder.

...