Передача переменной между действиями в пределах одних и тех же рельсов контроллера

#ruby-on-rails #ruby-on-rails-4

#ruby-on-rails #ruby-on-rails-4

Вопрос:

Мое действие show:

 def show
        # Multiple keywords

        if current_user.admin?
            @integration = Integration.find(params[:id])
        else            
            @integration = current_user.integrations.find(params[:id])
        end


        @q = @integration.profiles.search(search_params)
        @profiles = @q.result.where(found: true).select("profiles.*").group("profiles.id, profiles.email").includes(:integration_profiles).order("CAST( translate(meta_data -> '#{params[:sort_by]}', ',', '') AS INT) DESC NULLS LAST").page(params[:page]).per_page(20)
        @profiles = @profiles.limit(params[:limit]) if params[:limit]
end
  

Здесь может быть много разных фильтров, будь то с помощью Ransacker, с параметрами [:limit] или другими. В конце у меня есть подмножество профилей.

Теперь я хочу пометить все эти профили, которые являются результатом поискового запроса.

Модель профилей:

 def self.tagging_profiles
  #Some code
end
  

Я хотел бы создать действие в том же контроллере, что и show, которое будет выполнять self.tagging_profiles функцию @profiles из действия show, учитывая, что эти профили были отфильтрованы.

 def tagging
  @profiles.tagging_profiles
end
  

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

Обновить:

Вот как я обошел это, не знаю, насколько это чисто, но здесь:

def show # Несколько ключевых слов

         if current_user.admin?
            @integration = Integration.find(params[:id])
        else            
            @integration = current_user.integrations.find(params[:id])
        end


        @q = @integration.profiles.search(search_params)
        @profiles = @q.result.where(found: true).select("profiles.*").group("profiles.id, profiles.email").includes(:integration_profiles).order("CAST( translate(meta_data -> '#{params[:sort_by]}', ',', '') AS INT) DESC NULLS LAST").page(params[:page]).per_page(20)
        @profiles = @profiles.limit(params[:limit]) if params[:limit]

        tag_profiles(params[:tag_names]) if params[:tag_names]
end

   private
   def tag_profiles(names)
     @profiles.tagging_profiles
   end
  

На мой взгляд, я создал форму, вызывающую self:

 <%= form_tag(params.merge( :controller => "integrations", :action => "show" ), method: :get) do %>
        <%= text_field_tag :tag_names %>
        <%= submit_tag "Search", class: "btn btn-default"%>
       <% end %>
  

Это лучший способ сделать это?

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

1. Не могли бы вы уточнить свой вопрос?

2. @steel Я обновил свой вопрос!

3. Вы пробовали передавать @profiles.pluck(:id) через сеансы? Вы также можете передать информацию в скрытой форме на странице или через кнопку link_to, которую пользователь нажимает, чтобы запустить следующее действие. Google «rails, передающие переменные между контроллерами», и вы получите множество ответов, многие из них на SO.

4. Ваш вопрос неясен. Вы хотите реализовать функцию, которая будет помечать все профили, содержащиеся в @profiles ? Вы всегда будете выполнять этот процесс тегирования каждый раз, когда выполняется действие show?

5. Я думаю, я спрашиваю о том, что я хочу, чтобы пользователь мог выполнять поисковый запрос, иметь профили в представлении, а затем, если они будут удовлетворены, отмечать все из них, поэтому потребуется форма.

Ответ №1:

Действия общедоступного контроллера Rails всегда соответствуют http-запросу. Но здесь просто нет необходимости в 2 http-запросах. Простым решением было бы просто создать методы для частных контроллеров filter_profiles(params) tag_profiles(profiles) и просто вызывать их последовательно.

Вы также можете полностью извлечь эту проблему в ServiceObject, например:

   class ProfileTagger
    attr_reader :search_params          

    def initialize(search_params)
      @search_params = search_params
    end

    def perform
      search
      tag
    end

    def tag
     #tag found profiles
    end

    def search
     @profiles = #do the search
    end 
  end 
  

Поскольку обработка 30 000 записей является трудоемкой операцией, было бы разумно выполнять ее вне запроса rails в фоновом режиме. Эта структура позволит вам с легкостью делегировать эту операцию работнику sidekiq или delayed_job

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

1. Вы также выполняете много манипуляций с данными в контроллере вместо модели.

2. Как я могу пометить без запросов, но только с одним запросом и формой?

3. Думаю, я понял вашу проблему. Сначала вы показываете отфильтрованные данные, а затем хотите пометить их, верно?

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

Ответ №2:

Переменные экземпляра

Если вы хотите «поделиться» переменными данными между действиями контроллера, вам нужно взглянуть на ролевую @instance variables игру.

Экземпляр класса означает, что при отправке запроса у вас будет доступ к @instance переменной, пока вы находитесь в этом экземпляре класса, т.Е.:

 #app/controllers/your_controller.rb
Class YourController < ApplicationController
   before_action :create_your_var

   def your_controller
      puts @var
   end

   private

   def create_your_var
       @var = "Hello World"
   end
end
  

Это означает, что если вы хотите использовать данные в своем контроллере, я бы просто установил @instance variables , к которым вы сможете получить доступ с помощью любого количества различных действий, которые вы пожелаете

Методы экземпляра

Разница будет заключаться в том, как вы вызываете эти действия —

 #app/controllers/your_controller.rb
Class YourController < ApplicationController
   def action
      #-> your request resolves here
      method #-> calls the relevant instance method
   end

   private

   def method
      #-> this can be called within the instance of the class
   end
end