Nano Hash - криптовалюты, майнинг, программирование

Rails .joins() между таблицами и условие .where()

Резюме

Большое спасибо за твою помощь. У меня есть таблица locations и ads. Местоположение has_many :ads

Я хотел бы сделать запрос модели Location с моделью join с моделью Ad, чтобы отфильтровать записи по параметрам Location и Ad.

@locations = Location.joins(:ads).where(locations: location_params, ads: location_params[:ads_attributes])

Это метод location_params (пустые поля будут удалены другим методом, который работает нормально).

params.require(:location).permit(:country, {:ads_attributes => [:remote, :days]})

Это пример моего запроса. У меня есть метод, который удаляет пустые поля из location_params. Это работает нормально.

SELECT "locations".* FROM "locations" INNER JOIN "ads" 
ON "ads"."location_id" = "locations"."id" 
WHERE "ads_attributes"."remote" = $1  [["remote", "1"]]

В этом случае location_params имеет следующие поля:

<ActionController::Parameters {"ads_attributes"=>
<ActionController::Parameters {"remote"=>"1"} permitted: true>} permitted: true>

Это результат, пустой объект, даже если у меня есть записи с этими параметрами в моей таблице

#<Location::ActiveRecord_Relation:0x3fb83def8190>

Обновлять

  1. Первая проблема — решено с помощью Péter Tóth

Решение. Использование .includes(:ads) для отказа от повторного выполнения запроса с @locations[0].ads.

@locations = Location.joins(:ads).where(locations: {id: 1}, ads: {id: 1})

Проблема в том, что когда я выбираю из местоположения ads, он снова выполняет запрос и удаляет предыдущий фильтр ads.id = 1.

@locations[0].ads

В результате будет выбрано не только объявление с id=1, но и все объявления с этим @location[0].

  1. Второй выпуск

Я могу выполнить запрос:

@locations = Location.joins(:ads).where(locations: {id: 1}, ads: {id: 1})

Or

@locations = Location.joins(:ads).where(location_params)

Но нет

@locations = Location.joins(:ads).where(locations: location_params, ads: ads_params)

Но это можно решить следующим образом: выполнить первый запрос к местоположению.

@locations = Location.joins(:ads).where(@location_params.require(:location).permit(:id)).includes(:ads)

который возвращает все местоположения с этими параметрами, тогда мне нужно отфильтровать @locations на основе фильтров рекламы. Проблема в том, что я не могу выполнить следующий запрос.

@locations = @locations.joins(:ads).where(ads: @ads_params.require(:ads).permit(:id)).includes(:ads)

Ответы:


1

Вам нужно переписать запрос, так как ads_attributes не является таблицей, попробуйте это

ads_params = @ads_params.require(:ads).permit(:id).to_h
location_params = @location_params.require(:location).permit(:id).to_h
@locations = Location.joins(:ads).where(locations: location_params, ads: ads_params)

Надеюсь, это поможет!

12.03.2017
  • Извините, я не могу выбрать конкретный столбец с помощью { country: location_params[:country] }. Есть несколько полей и есть метод, который удаляет их, если они пусты. Если location_params[:country] пусто, то оно будет удалено и станет nil. Я хотел бы просто ввести location_params в запрос, не указывая конкретный столбец для выбора. Знаете ли вы, как исправить следующий запрос, чтобы он работал? @locations = Location.joins(:ads).where(locations: new_params, ads: new_params[:ads_attributes]) Спасибо 12.03.2017
  • Я отредактировал свой ответ, это должно решить вашу проблему. 12.03.2017
  • Спасибо RSB, все равно не работает. это location_params <ActionController::Parameters {"country"=>"IT", "location"=>"Leizpig"} permitted: true>, а это ads_params <ActionController::Parameters {"remote"=>"1"} permitted: true> и запрос пустой #<Location::ActiveRecord_Relation:0x3f9eeac68e00> 12.03.2017
  • Я не могу понять, как это решить. Я думаю сделать 2 шага: 1. сначала я фильтрую все на основе модели местоположения 2. я фильтрую результат на основе модели рекламы. Если у вас есть какие-либо советы, скажите мне, тогда мы отредактируем ваш ответ с окончательным ответом, и я приму его. 12.03.2017
  • Я думаю, может быть, проблема не в запросе, а в ассоциации между местоположением и рекламой. Я выбираю из модели местоположения, но в Location has_many:ads. Даже если я смогу сделать запрос с соединением, то, когда я сделаю location.ads, он потеряет фильтр, который я сделал для объявления. 12.03.2017
  • Вы хотите отредактировать свой ответ с содержанием другого обсуждения? Я также думаю, что этот вопрос должен иметь вас как правильный ответ. stackoverflow.com/questions/42760581 / 13.03.2017

  • 2

    @locations[0].ads будет получать все ads для первого объекта местоположения, несмотря ни на что. Конечно, он будет выполнять процесс выборки только в том случае, если они еще не были получены. Одним из решений является боковая загрузка ads:

    @locations = Location.joins(:ads).where(locations: {id: 1}, ads: {id: 1}).includes(:ads)
    @locations[0].ads
    

    Таким образом, вы можете избежать проблемы N + 1 запросов. Но вы должны использовать его осторожно, так как @locations[0].ads.reload загрузит все ads независимо от того, какой фильтр вы использовали ранее.

    Совет: зависит от вашей цели, если вам нужно только ads по каким-то критериям, то я бы посоветовал начать с Ad.join(:location).where(...).includes(:location)...

    Обновить

    Это работает для меня, если я отправлю GET /locations?location[country]=IT&ad[remote]=1:

    class LocationsController < ApplicationController
      def index
        @locations = Location.joins(:ads).where(locations: location_filters, ads: ad_filters).includes(:ads)
      end
    
      private
    
      def location_filters
        params.require(:location).permit(:country)
      end
    
      def ad_filters
        params.require(:ad).permit(:remote, :days)
      end
    end
    

    Или, если у вас нет всех колясок, доступных в каждом случае, вы можете создать запрос:

    class LocationsController < ApplicationController
      def index
        @locations = Location.joins(:ads).includes(:ads)
        @locations = @locations.where(locations: location_filters) if location_filters.present?
        @locations = @locations.where(ads: ad_filters) if ad_filters.present?
      end
    
      private
    
      def location_filters
        params.fetch(:location, {}).permit(:country)
      end
    
      def ad_filters
        params.fetch(:ad, {}).permit(:remote, :days)
      end
    end
    
    12.03.2017
  • Спасибо. Это решило эту конкретную проблему, когда я не мог сделать @locations[0].ads, но теперь моя проблема заключается в заполнении @locations. В моем случае я не могу использовать id или определенный параметр, потому что поля удаляются другим методом, когда они пусты. Поэтому я хотел бы использовать решение @RSB, но когда я пытаюсь выполнить запрос в своей консоли или в отладке, он не работает. 13.03.2017
  • Извините, но проблема была в том, что параметры нужно было преобразовать .to_h 13.03.2017
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

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

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..