[Ruby] Have a one-to-many relationship between models with Rails associations

3 minute read

Introduction

After I’m a Rails newbie and associated tables with associations, I had a hard time not passing parameters to the action method, so I will write an article. The goal is to put the information of menus in Place and output it on the screen.

*Because it is the first post, there may be some parts that are difficult to understand, some parts are incorrect. We will do our best to describe the information as accurately as possible, but we appreciate your understanding. We would be happy if you could give us your comments in the comments!

Check the Place and Menu columns for the time being

irb(main):005:0> Place.column_names
=> ["id", "name", "message", "created_at", "updated_at", "user_id"]
irb(main):006:0> Menu.column_names
=> ["id", "title", "price", "message", "created_at", "updated_at", "place_id"]

It will be as above.

The logged-in User can post his favorite cafe → Menu information can be added to the cafe. Function.

Join tables by association

``

app/models/place.rb
class Place <ApplicationRecord
  belongs_to :user
  has_many :menus
end

In Rails, the naming convention is important, so be careful not to confuse this singular and plural. Have (one) place for (one) user and (several) menus for (one) place.

belongs_to has_many (has a lot)…it’s easy to understand!

app/models/menu.rb


class Menu <ApplicationRecord
  belongs_to :place
end

Menu.rb looks like this.

For now, the connection between the tables is completed.

places_controller.rb


    [1] pry(#<PlacesController>)> @place
=> #<Place:0x00007f9d1e88cc10
 id: 3,
 name: "hoge Coffee",
 message: "I like the calm atmosphere at my nearest cafe from home.",
 created_at: Thu, 18 Jun 2020 00:05:20 UTC +00:00,
 updated_at: Thu, 18 Jun 2020 13:14:42 UTC +00:00,
 user_id: 1>
[2] pry(#<PlacesController>)> params
=> <ActionController::Parameters {"controller"=>"places", "action"=>"show", "id"=>"3"} permitted: false>

I want to register the menu from views/places/show.html.erb, so check the parameters. This is the information on the cafe where you want to register the menu this time.

ruby:places/show.html.erb


  <%= link_to'Register menu', new_menu_path(id: @place.id) %>

To the new action of menus_controller to register the menu.

If you do not pass an argument to the _path helper at this time, you can not search place with the new action of menus_controller.


class MenusController <ApplicationController

  def new
    @menu = Menu.new
    @place = Place.find_by(id: params[:id])
  end
(Omitted)

Input form ↓

ruby:menus/new.html.erb


<%= form_with model:@menu, local: true do |f| %>
<h2>Register menu</h2>
<p>Cooking name :<%= f.text_field :title %></p>
<p>Price :<%= f.text_field :price %></p>
<%= f.hidden_field :place_id, :value => @place.id %>
<%= f.submit'register' %>
<% end %>

place_id is not something to enter, so we will receive the value passed in hidden_field.

It is how to receive place_id in create action, but it will be received in the input form when registering the menu.


def create
# Receive the parameters received in the input form here
    @menu = Menu.create(
      title: menus_params[:title],
      price: menus_params[:price],
      place_id: menus_params[:place_id]
    )
# I will check if it is properly received here
    binding.pry
end

(Omitted)

private

  def menus_params
    params.require(:menu).permit(:title, :price, :place_id)
  end

(Omitted)

Fill out the form for confirmation. result···

``


[1] pry(#<MenusController>)> menus_params
=> <ActionController::Parameters {"title"=>"Ice Coffee", "price"=>"280", "place_id"=>"3"} permitted: true>

I was able to receive the place_id properly.

Now you can accept parameters with a one-to-many relationship (menus for place).

    <% @place.menus.each do |menu| %>
        <p><%= menu.title %> <%= menu.price %></p>
    <% end %>

The registered menu can be output like this.

[1] pry(#<PlacesController>)> @place.menus
  (Omitted)
=> [#<Menu:0x00007ffda376a4c8
  id: 37,
  title: "Chocolate cake",
  price: 250,
  created_at: Thu, 18 Jun 2020 01:36:00 UTC +00:00,
  updated_at: Thu, 18 Jun 2020 01:36:00 UTC +00:00,
  place_id: 3>,
 #<Menu:0x00007ffda3773eb0
  id: 44,
  title: "Ice coffee",
  price: 280,
  created_at: Fri, 19 Jun 2020 00:24:50 UTC +00:00,
  updated_at: Fri, 19 Jun 2020 00:24:50 UTC +00:00,
  place_id: 3>]

You can check the menu registered with @place.menus because it is linked with the association.