I wanted a function to sort posts by date and time and the number of likes in the original application, so I managed to implement it while being quite addicted, so I will leave it as a memorandum.
__ ● Environment __ ・ Ruby 2.6 series ・ Rails 5.2 series __ ● Library used __ ・ Slim ・ Devise __ ● Like function is implemented __ ・ [Rails] Implementation of Like Function (Slim and devise are also introduced in this article)
(I'm sorry it doesn't look good ...)
h1 post list = form_with model: @post, url: search_path, method: :get, local: true do |form| = form.select :keyword, [ ['Posts are newest', 'new'], ['Posts oldest', 'old'], ['In descending order of likes', 'likes'], ['In ascending order of likes', 'dislikes'], ] = form.submit #================The part that was originally implemented========================
>> __ ・ Let's break down what is happening. __
>>```ruby
= form_with model: @post, url: search_path,
method: :get, local: true do |form|
__-The
`Post model`
is specified as the model used in the form. This will send the data with the valueparams [: post]
. __
__ ・ After searching, we will prepare a page for displaying search results, so set the path to `` `search_path``` and send it as a GET request. __
__ ・
local: true
. If this is not specified in form_with, it will be considered as Ajax communication. If you do not use JS, you must add it or it will not be rendered. __
= form.select :keyword, [ ['Posts are newest', 'new'], ['Posts oldest', 'old'], ['In descending order of likes', 'likes'], ['In ascending order of likes', 'dislikes'], ] = form.submit
>> __ ・ You can create a pull-down form by using the select method.
The usage is like `` `select (" object "," method "," choice ")` ``. __
>> __ ・ ``` The first argument object``` corresponds to the `` `post object` ``, but omit it when using form_with. __
>> __ ・ ``` The second argument method``` is a` `thing that is sent as a parameter to the` `controller, so please describe it freely. __
__ In this case, since keyword is specified, it will be sent as `` `params [: keyword]` ``. __
>> __ ・ In the choice``` part, which is the third argument,
```[ [Value to be displayed by pull-down 1,Parameters sent to the action],
[Value to be displayed in the pull-down part 2,Parameters sent to the action],
[Value to be displayed in pull-down, Part 1, Parameter sent to action]] Specify `` `. __
### 2. Edit the routing
>```ruby:config/routes.rb
Rails.application.routes.draw do
#================The part that was originally implemented========================
devise_for :users
resources :users
root to: 'posts#index'
resources :posts, only: [:index, :new, :create, :show, :edit, :update] do
resource :favorites, only: [:create, :destroy]
end
#================The part that was originally implemented========================
#Send search results to the search action of the posts controller
+ get 'search' => 'posts#search'
end
class PostsController < ApplicationController . . . def search selection = params[:keyword] @posts = Post.sort(selection) end . . . end
>> __ ・ Create a search action. In params [: keyword], the value selected in the sort form is received and stored in a local variable called selection. __
>> __ ・ `sort` is an instance method for Post. After that, define the Post model class so that posts will be retrieved in the order of sorting by the value of selection. __
### 4. Define the sort instance method in the Post model.
>```ruby:app/models/user.rb
class Post < ApplicationRecord
.
.
.
def self.sort(selection)
case selection
when 'new'
return all.order(created_at: :DESC)
when 'old'
return all.order(created_at: :ASC)
when 'likes'
return find(Favorite.group(:post_id).order(Arel.sql('count(post_id) desc')).pluck(:post_id))
when 'dislikes'
return find(Favorite.group(:post_id).order(Arel.sql('count(post_id) asc')).pluck(:post_id))
end
end
.
.
.
end
__ ・ Since it is an instance method definition, self is added. __
__ ・ The case statement defines the conditions for sorting according to the value passed to selection. __
__ ↓ Sort by date __
when 'new' return all.order(created_at: :DESC) when 'old' return all.order(created_at: :ASC)
>> __ ↓ Sort by number of likes __
>>```ruby
when 'likes'
return find(Favorite.group(:post_id).order(Arel.sql('count(post_id) desc')).pluck(:post_id))
when 'dislikes'
return find(Favorite.group(:post_id).order(Arel.sql('count(post_id) asc')).pluck(:post_id))
__ · Favorite.group (: post_id) will group posts with the same
post_id
. __
__ · order (Arel.sql ('count (post_id) desc')),
count how many user_ids are stored in grouped posts and sort from the most
(that is, how much I'm counting if it's liked). __ __ʻArel.sql () is a SQL injection countermeasure`. __
__ ・ In pluck (: post_id),
post_id itself is acquired
. If you do not describe this, the find corresponding to the call to Post will not be found and an error will occur. __
_ * Currently, the problem that posts with 0 likes are not displayed is not supported. I'm sorry…. I will add it as soon as it is resolved. _
h1 search results = form_with url: search_path, method: :get, local: true do |form| = form.select :keyword, [ ['Posts are newest', 'new'], ['Posts oldest', 'old'], ['In descending order of likes', 'likes'], ['In ascending order of likes', 'dislikes'], ] = form.submit
>> __ ・ Create a setatch.html.slim file in the app / views / posts directory and describe it as above. __
>> __ ・ The content described here is exactly the same as the content described in posts / index.html.slim, so it will be partialized. __
### 6. Partial view
> #### __6-1. Partialization of search form __
>```ruby:app/views/posts/_select_form.html.slim
= form_with model: @post, url: search_path, method: :get, local: true do |form|
= form.select :keyword, [ ['Posts are newest', 'new'],
['Posts oldest', 'old'],
['In descending order of likes', 'likes'],
['In ascending order of likes', 'dislikes'],
]
= form.submit
__ · Create a
_select_form.html.slim
file in the app / views / posts directory and port the entire pull-down menu code. __
__6-2. Partialization of post list & search result list __
>> __ ・ Create a `_result.html.slim` file in the app / views / posts directory and port the entire code for displaying the post list. __
> #### __6-3. Render to each view __
>```ruby:app/views/posts/index.html.slim
h1 post list
= render 'select_form'
= render 'result'
h1 search results = render 'select_form' = render 'result'
#### that's all.
## Finally
This completes the sort function implementation!
To be honest, I'm not confident in many parts, so I'd be very happy if you could tell me anything wrong!
## Article that I was very helpful
[How to implement search function without gem? Supports multiple tables! ](Https://prokyou.com/rails/nogemsearch/)
[[Rails] How to use select to create a select box with a complete understanding form](https://310nae.com/rails-selectbox/)
[select (ActionView::Helpers::FormOptionsHelper) - APIdock](https://apidock.com/rails/ActionView/Helpers/FormOptionsHelper/select)
Recommended Posts