[RubyOnRails] How to implement pull-down in form_with based on table data


While I was thinking of introducing pull-down selection to form_with and implementing it, there were some places where I repeated trial and error, so I will leave it as a reminder.


・ Ruby 2.6.5 ・ Rails 6.0.3

Premise situation and what you want to do


There is a shop table where you can register restaurant information. There is a station table that contains station data for the Yamanote line as a list. The two tables have a many-to-many relationship and form an association via an intermediate table (shop_station table).

Thing you want to do

I want to implement the following functions. ** ① When creating shop data, I want to select the nearest station from the pull-down menu and register it. ** ** ** ② Registration of the nearest station is optional and does not have to be registered. You can register up to 2 stations. ** ** ** ③ Naturally, I want to register all the nearest stations at once by submitting the form once. ** **

I will leave the above implementation procedure as a reminder.

Well, I will write the procedure below.

(1) Create and implement pull-down options based on table data

This time we will implement the form in the new action of the shop controller. I will extract the code first and write it.



before_action :set_select_lists, only: [:new]

def new
    @shop = Shop.new

  def set_select_lists
    @stations = Station.all.map {|station| [station.name, station.id] }



  = form_with model: [@owner, @shop], html: {class: "shopform"}, local: true do |f|

-#Omission(Indentation is appropriate for syntax highlighting. Excuse me. Indent according to haml notation)

= f.select :station_ids, @stations,{},{class: "select"}
= f.select :station_ids, @stations,{},{class: "select"}
* By registering the nearest station, it will be displayed in the station designation search.

The explanation of each is as follows.

Controller @stations is creating the data that will be the basis for this choice. The following is a rough explanation.

Station.all All data in the Station table

Station.all.map {~} For each data (record) in the Station table all data, process according to {}

Station.all.map {|station| [station.name, station.id]} Generates a hash with each record as station, station.name (value in the name column of each record) as the key, and station.id (value in the id column) as the value.


= f.select :station_ids, @stations,{},{class: "select"}

Send data with form_with. Create a pull-down with f.select. When sending data, send it with the key: station_ids. Choices are based on @stations. The class name is select.

The key defined in the controller is ** "choices displayed in the pull-down" **, and the value is ** "value sent by params" **. When people choose, they want to choose by station name, and when registering data, they want to associate by id. That's why I set the key and value like this.

The figure that implements these is as follows.

スクリーンショット 2020-06-29 23.56.04.png

Two of the same pull-downs are lined up and one is open. Certainly station.name is displayed as an option.

② Make the registration of the nearest station optional

In the image above, since the list is made from table data, ** there is no "choice" of "do not select a station". ** ** I rewrote the controller as follows to make the common "Please choose from the following".


def set_select_lists
    @stations = Station.all.map {|station| [station.name, station.id] }.unshift(["Please choose from the following", nil])

I added .unshift (["Please choose from below", nil]) to @stations earlier. unshift is a method that adds an element to the very beginning of an array. We added the option to pass nil to the value with the sentence "Please choose from the following" as the key.

Adding a record such as "there is no nearest station" to the table data itself is not preferable because the number of records in the intermediate table will increase unnecessarily, so I added the option to set the value to nil.

スクリーンショット 2020-06-30 0.01.57.png

Now you have successfully implemented the pull-down you want.

③ Register all the nearest stations at once by submitting the form once

I thought that I could register at this point, but when I actually skipped the data from params, the following problem occurred. ** Since both pull-downs send data with the key with the same name station_ids, the result is that the second value overwrites the first value and only one value is sent. ** **

It was obvious when I looked at binding.pry. However, what I want to do here is to send and register multiple station_ids. That is, I want to send ** station_ids as an array **

I think there are several ways to do it, but I rewrote the view as follows (this is probably a power technique, but I was able to use it in the form after that)


= f.select :station_ids, @stations,{},{name: 'shop[station_ids][]', class: "select"}
= f.select :station_ids, @stations,{},{name: 'shop[station_ids][]', class: "select"}

The name attribute is added to the previous state. If you add the name attribute in form_with, you can specify ** "How do you send the params?" **.

If you actually look at the params in binding.pry, you can see how the data is sent. station_ids are sent in the form ** params [: shop] [: station_ids] **.

I wanted to make this an array, so by adding [] at the end of the name attribute, I can safely send both data in the form of an array.


def shop_params
    params.require(:shop).permit(:name, :address, :capacity, :owner_id, :genre_id, :mark_ids,introduces_attributes: [:content, :image, :number],station_ids: [])

By the way, I mentioned earlier that the data was sent in the form of params [: shop] [: station_ids], so as mentioned above, with the strong parameter ** First, require: shop and press the key in it. By permitting, the data will be entered safely. ** ** I understood this well in binding.pry. Was funny.

At the end

The method of specifying with the name attribute is quite powerful, so please tell me if you meet a smarter method. However, I implemented each value of the form after this quite a bit.

I learned the most from seeing how params are sent in binding.pry.

Recommended Posts

[RubyOnRails] How to implement pull-down in form_with based on table data
How to clear all data in a particular table
How to store Rakuten API data in a table
How to implement search functionality in Rails
How to implement date calculation in Java
How to implement Kalman filter in Java
How to get date data in Ruby
How to implement coding conventions in Java
How to implement ranking functionality in Rails
How to use environment variables in RubyOnRails
How to implement asynchronous processing in Outsystems
How to overwrite Firebase data in Swift
How to implement gem "summer note" in wysiwyg editor in Ruby on Rails
How to implement a like feature in Rails
How to easily create a pull-down in Rails
[Rails] How to easily implement numbers with pull-down
How to implement optimistic locking in REST API
[Ruby on Rails] How to install Bootstrap in Rails
Notes on how to write comments in English
How to implement Pagination in GraphQL (for ruby)
How to implement image posting function using Active Storage in Ruby on Rails
How to make a unique combination of data in the rails intermediate table
How to implement guest login in 5 minutes in rails portfolio
How to create a data URI (base64) in Java
[Ruby On Rails] How to reset DB in Heroku
Summary of how to implement default arguments in Java
Notes on how to use regular expressions in Java
[Ruby On Rails] How to search and save the data of the parent table from the child table
How to use JSON data in WebSocket communication (Java, JavaScript)
How to run npm install on all projects in Lerna
How to implement infinite scrolling (page nate) in Swift TableView
How to display a graph in Ruby on Rails (LazyHighChart)
How to implement one-line display of TextView in Android development
How to switch Java in the OpenJDK era on Mac
How to deploy on heroku
[Rails] How to implement scraping
[Java] How to implement multithreading
How to implement a job that uses Java API in JobScheduler
How to automatically operate a screen created in Java on Windows
How to switch Java version with direnv in terminal on Mac
[Behavior confirmed in December 2020] How to implement the alert display function
How to get and add data from Firebase Firestore in Ruby
How to implement UI automated test using image comparison in Selenium
How to get JDK 11 on your mac in a comfortable way
How to use Lombok in Spring
Implement Table Driven Test in Java 14
How to find May'n in XPath
How to deploy jQuery on Rails
How to add columns to a table
How to hide scrollbars in WebView
How to use the form_with method
How to deploy Laravel on CentOS 7
How to run JUnit in Eclipse
How to iterate infinitely in Ruby
Try to implement Yubaba in Ruby
How to "hollow" View on Android
How to use Spring Data JDBC
[Rails] How to write in Japanese
How to run Ant in Gradle
[Java] How to update Java on Windows
How to master programming in 3 months