Расширенный поиск с помощью Rails - проблема с запросом Active Record SQl

Я построил функцию поиска поверх своего приложения rails, где я могу искать и фильтровать по имени и полу пользователя. Поиск работает исправно, единственное, он работает не точно!

Например, если я ищу пользователей-мужчин, в результатах поиска также будут указаны пользователи-женщины. И я думаю, это связано с тем, что я использую запрос ActiveRecord, в котором я сравниваю столбец пола в таблице пользователей со вставленными параметрами, и потому что «женский» и «мужской» - два очень похожих слова, и его результаты связаны с двумя атрибуты. Это запрос ActiveRecord, который я использовал и который работает (хотя и не совсем точно):

"gender LIKE ? ", "%#{params[:gender]}%"

Поэтому я использовал другой запрос ActiveRecord:

"gender: %#{params[:gender]}%"

Второй запрос, к сожалению, все ломает. Я получаю эту ошибку в своем терминале:

SQLite3::SQLException: unrecognized token: ":": SELECT "users".* FROM "users" WHERE (gender: %Male%))

Предполагается, что эти запросы ActiveRecord принадлежат search_controller моей «поисковой» модели. Это мой контроллер:

  def index
    if params[:username] || params[:gender].present?
        @search = User.where('true').paginate(page: params[:page], per_page: 10)
        @search = User.where("name LIKE ? ", "%#{params[:username]}%") unless params[:username].blank?
        @search = User.where("gender LIKE ? ", "%#{params[:gender]}%") unless params[:gender].blank?
    else
        @search = User.all.paginate(page: params[:page], per_page: 10)
    end
  end

  def create
     @search = Search.create(username: params[:username], gender: params[:gender])
     redirect to @search
  end

  private

  def search_params
    params.require(:search).permit(:users, :gender)
  end

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

<h1> Your Search Results </h1>

<% if @search.nil? %>
  <p> No Results Found </p>


<% else %>

<ul class = "users">
  <% @search.each do |user| %>
    <%= user.name %>
    <%= user.gender %>
  <% end %>

</ul>

<% end %>

<p><%= link_to 'All Users',  users_path %></p>

Это небольшое видео, в котором я могу объяснить, что я хочу делать: https://drive.google.com/file/d/1G5FYytvmdI6iKjmwlH16NeftGwsEnLQU/view?usp=sharing

🤔 А знаете ли вы, что...
SQL поддерживает транзакции с использованием команд BEGIN, COMMIT и ROLLBACK.


77
2

Ответы:

Использование LIKE ? делает ваш код уязвимым для SQL-инъекции, поэтому я определенно рекомендую вам изменить свой подход.

Думаю, вы решите проблему, используя что-то вроде

User.where("name = ? AND gender = ?", params[:username], params[:gender])

Также используйте Руководство по запросам Active Record в качестве ссылки каждый раз, когда вы используете запросы. Там вы найдете много полезного.


Две проблемы: 1) чтобы точно соответствовать параметру, который вы можете сделать

@search = User.where(gender: params[:gender]) unless params[:gender].blank?

Остальное, что вы оставили, касается лежащего в основе LIKE clausa, и если вы хотите сделать это с помощью LIKE, это правильный синтаксис

@search = User.where("gender LIKE ? ", "#{params[:gender]}") unless params[:gender].blank?

2) вы перезаписываете переменную @search, поэтому, если у вас есть оба параметра, ваш запрос параметра имени никогда не останется. Попробуй в конце

@search = User.all
@search = @search.where("name LIKE ? ", "%#{params[:username]}%") unless params[:username].blank?    
@search = @search.where("gender LIKE ? ", "%#{params[:gender]}%") unless params[:gender].blank?