[Ruby on Rails] 1 model CRUD (Routing Main)

The opportunity to write this article

Recently I started answering questions at tetatail to deepen my understanding of rails. Looking at the questions there, some people may feel that they are missing basic knowledge when implementing CRUD, and it seems as if they were looking at themselves about a year ago, so it should be useful. I wrote this article. What is CRUD Also, by understanding this one CRUD, even when the number of models increases to two or three, it feels like applying based on this basic knowledge, so I think it is good to learn about CRUD of one model first. ..

Target audience

--Those who want to learn about routing --Those who do not know what params [: id] refers to ――I was about a year ago

Overview

Describes the CRUD functionality of one model (model name: Post, column: title, content) in as much detail as possible. The description of the model is rarely mentioned in this article. The routing and controller will be the main. By the way, routing appears persistently. Also, please forgive that point because the code is also described as it is, where it is usually summarized.

Flow of this article

  1. Create a new project
  2. Creating a Post model
  3. Routing settings
  4. Create Posts Controller 5.index action definition (no description of contents)
  5. New action definition, new registration form creation
  6. create action definition 6.index action content description 7.show action definition, detail page creation
  7. edit action definition, edit form creation
  8. update action definition
  9. destroy action definition I will explain in the order of.

environment

% ruby -v
ruby 2.7.1p83 (2020-03-31 revision a0c7c23c9c) [x86_64-darwin19]

% rails -v
Rails 6.0.3.2

% postgres --version
postgres (PostgreSQL) 9.6.18

1. Create a new project

Create an app with the rails new command. This time, the app name will be ʻone_model_crud`.

rails new [app name](one_model_crud) -d postgresql

Edit database.yml

database.yml


default: &default
  adapter: postgresql
  encoding: unicode
  username: <%= ENV['PG_USERNAME'] %> #username set in postgresql
  password: <%= ENV['PG_PASSWORD'] %> #password set in postgresql
  # For details on connection pooling, see Rails configuration guide
  # https://guides.rubyonrails.org/configuring.html#database-pooling
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
% rails db:create
Created database 'one_model_crud_development'
Created database 'one_model_crud_test'

% rails s

Go to http: // localhost: 3000 /. スクリーンショット 2020-08-15 9.46.35.png

Although it deviates from the main subject, this time view uses slim, bootstrap for styling, and pry-rails as a debugging tool.

slim conversion

Introduction of bootstrap

Now you are ready.

2. Creating a Post model

rails g model Create a model with the model name (singular).

% rails g model post

Add a title and content columns.

XXXX_create_posts.rb


class CreatePosts < ActiveRecord::Migration[6.0]
  def change
    create_table :posts do |t|
      t.string :title
      t.text   :content

      t.timestamps
    end
  end
end

Reflect the created database information.

% rails db:migrate
== 20200815005104 CreatePosts: migrating ======================================
-- create_table(:posts)
   -> 0.0271s
== 20200815005104 CreatePosts: migrated (0.0272s) =============================

Let's check it on the console.

% rails c
irb(main):001:0> Post.new
=> #<Post id: nil, title: nil, content: nil, created_at: nil, updated_at: nil>
irb(main):002:0> Post.new(title: 'Title 1', content: 'Content 1').save
   (0.3ms)  BEGIN
  Post Create (7.9ms)  INSERT INTO "posts" ("title", "content", "created_at", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id"  [["title", "Title 1"], ["content", "Content 1"], ["created_at", "2020-08-15 01:03:24.246072"], ["updated_at", "2020-08-15 01:03:24.246072"]]
   (6.8ms)  COMMIT
=> true

You have created a Post model. Now let's do this in the browser.

3. Routing settings

Set the routing to access posts # index when accessing http: // localhost: 3000 /.

routes.rb


Rails.application.routes.draw do
  # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
  root to: "posts#index"
  resources :posts
end

The resources: model (plural) will generate the routing for the model's seven basic actions index, new, create, show, edit, update, and destroy.

You can also limit actions by writing resources: model (plural), only:: index orresources: model (plural), only:% i [index].

Now let's look at the generated routing in the console.

% rails routes
     Prefix Verb       URI Pattern               Controller#Action
       root  GET      /                           posts#index
       posts GET      /posts(.:format)            posts#index
             POST     /posts(.:format)            posts#create
    new_post GET      /posts/new(.:format)        posts#new
   edit_post GET      /posts/:id/edit(.:format)   posts#edit
        post GET      /posts/:id(.:format)        posts#show
             PATCH    /posts/:id(.:format)        posts#update
             PUT      /posts/:id(.:format)        posts#update
             DELETE   /posts/:id(.:format)        posts#destroy

A routing like the one above has been created.

--Prefix will be explained later. --Verb is an HTTP method. --ʻURI Pattern points to the URL after http: // localhost: 3000. --Controller # Action` refers to which action of which controller is performed when the URL is accessed.

With that in mind, let's take a look at http: // localhost: 3000 /.

This means that when you visit http: // localhost: 3000 /, you will perform the index action on the posts controller.

4. Create Posts Controller

Create a controller with the rails g controller model (plural).

% rails g controller posts
Running via Spring preloader in process 31151
      create  app/controllers/posts_controller.rb
      invoke  erb
      create    app/views/posts
      invoke  test_unit
      create    test/controllers/posts_controller_test.rb
      invoke  helper
      create    app/helpers/posts_helper.rb
      invoke    test_unit
      invoke  assets
      invoke    scss
      create      app/assets/stylesheets/posts.scss

Only ʻapp / controllers / posts_controller.rb and ʻapp / views / posts are used, so you can delete them.

5.index action definition (no description of contents)

PostsController.rb


class PostsController < ApplicationController
  def index
  end
end

The contents will be set after the Post can be created.

Create index.slim in app / views / posts / and write the following

index.slim


h1 Posts#index

Now you are ready. Now actually access http: // localhost: 3000 /

% rails s

Flow when accessing

  1. Perform the PostsController index action
  2. View views / posts / index.slim It will be.

When you actually access it, the following screen will be displayed.

スクリーンショット 2020-08-15 11.12.19.png

6. New action definition, new registration form creation

As an implementation flow

  1. Installation of link
  2. PostsController new action
  3. Transition to new.slim
  4. PostsController create action It looks like.

1. Installation of link

First, create a link to access the new registration screen. What you need here is ** Prefix **. The link can be created by writing the following form. = link_to'Character to display', Prefix_path By writing like this, you can generate a link to access the URI Pattern of Prefix_path. I will actually describe it.

index.slim


h1 Posts#index
= link_to 'sign up', new_post_path

This link is where Prefix transitions to ʻURI Pattertn` in ** new_post **. Let's take a look at the routing of the new action.

Prefix Verb       URI Pattern               Controller#Action
new_post GET      /posts/new(.:format)        posts#new

You have now created a link to access the new registration screen. スクリーンショット 2020-08-15 11.42.12.png

Click the new registration link and the URL will change to / posts / new. (* I get an error because I haven't defined a new action yet)

スクリーンショット 2020-08-15 11.43.12.png

2. PostsController new action

PostsController.rb


def new
  @post = Post.new
end

Post.new creates an instance of the Post model and assigns that instance to @post.

3. Transition to new.slim

new.slim


.container
  h1.mt-4 New registration
  = form_with url: posts_path, model: @post do |form|
    .form-group
      = form.label :title, 'title'
      = form.text_field :title, class: 'form-control'
    .form-group
      = form.label :content, 'Contents'
      = form.text_area :content, class: 'form-control'
    = form.submit 'Registration', class: 'btn btn-primary'

Click here for form_with => How to use form_with

To briefly explain = You can set the transition destination when you press submit with form_with posts_path.

I would like to see the routing of the create action here.

Prefix Verb       URI Pattern               Controller#Action
posts GET      /posts(.:format)            posts#index
      POST     /posts(.:format)            posts#create

If nothing is described in Prefix, it will be the Prefix that exists at the beginning by following the above. In this case, Prefix is posts. Therefore, there are two types of posts_path, posts # index and posts # create. Verb (** HTTP method **) is how to judge these two. For form_with, the default HTTP method is set to POST. This means that ** posts_path ** written in new.slim means execute the create action of PostsController.

4. PostsController create action

First, check what kind of parameters are sent.

PostsController.rb


def create
  binding.pry
end

Let's see in the console how the data is sent by writing.

 9: def create
 => 10:   binding.pry
    11: end

[1] pry(#<PostsController>)> params
=> <ActionController::Parameters {"authenticity_token"=>"d9j/87bg84JqMg5cPr7HwMKi8PIbw8gmEhMj4EvgIblmRKqdmGAdmk1THcW9095M2cBdQxGigM/PZ+VYl9ZGYA==", "post"=>{"title"=>"Title 2", "content"=>"Content 2"}, "commit"=>"Registration", "controller"=>"posts", "action"=>"create"} permitted: false>
[2] pry(#<PostsController>)> params[:post][:title]
=> "Title 1"
[3] pry(#<PostsController>)> params[:post][:content]
=> "Content 2"

By writing like this, I was able to confirm the contents. Then save this.

PostsController.rb


def create
  @post = Post.new(title: params[:post][:title], content: params[:post][:content])
  @post.save
end

Then you can save it. However, this time, we will save it using a mechanism called strong parameters that prevent invalid parameters.

PostsController.rb


def create
  @post = Post.new
  @post.save(post_params)
  redirect_to posts_path
end

private

def post_params
  params.require(:post).permit(:title, :content)
end

The modified code looks like this. This time, the conditional branch code is not described in the if statement because the title and content can be saved even if they are empty. The last description of the create action redirect_to posts_path causes the url to transition to/, that is, to execute the index action of PostsController.

6.index action content description

Now that the data has been generated by the create action, the next step is to acquire and display the data.

PostsController.rb


def index
 @posts = Post.all
end

You can get all the data of the model with model .all and assign the obtained data to @posts. @posts is plural because it is expected to contain multiple data. By the way, the data is included in the following form.

[#<Post:0x00007f94bc4d83b8 id: 1, title: "Title 1", content: "Content 1", created_at: Sat, 15 Aug 2020 05:19:09 UTC +00:00, updated_at: Sat, 15 Aug 2020 05:19:09 UTC +00:00>,
 #<Post:0x00007f94bc4ae838 id: 2, title: "Title 2", content: "Content 2", created_at: Sat, 15 Aug 2020 05:19:22 UTC +00:00, updated_at: Sat, 15 Aug 2020 05:19:22 UTC +00:00>]

Let's display these.

index.slim


.container
  h1.mt-4 Posts#index
  = link_to 'sign up', new_post_path

  //Postscript
  - @posts.each do |post|
    .card.my-4
      .card-header
        = post.title
      .card-body
        p.card-text
          = post.content

@posts is defined in the index action. It is fetched one by one with each method, and one fetched data is put in the post. = post.title, = post.content refers to the title column and content column of post data. The screen will look like the one below. スクリーンショット 2020-08-15 14.28.14.png

7.show action definition, detail page creation

First, set up a button to move to the details screen under each data.

index.slim


.container
  h1.mt-4 Posts#index
  = link_to 'sign up', new_post_path

  - @posts.each do |post|
    .card.my-4
      .card-header
        = post.title
      .card-body
        p.card-text
          = post.content
        //Postscript
        = link_to 'Details', post_path(post), class: 'btn btn-success mr-2'

Notice that it takes a post as the ** argument of post_path **. Let's take a look at the routing of the show action.

Prefix Verb       URI Pattern               Controller#Action
    post GET      /posts/:id(.:format)        posts#show

The URI Pattern has a: id and this value changes dynamically. (Example: / posts / 1, / posts / 7) If only post_path is used, the id is unknown, so take an argument. (This time post) By doing this, you can get the id of the post and you can transition to / posts /: id. Now let's see what parameters are sent to the show action.

PostsController.rb


def show
  binding.pry
end

Stop at binding.pry and check the console

pry(#<PostsController>)> params
=> <ActionController::Parameters {"controller"=>"posts", "action"=>"show", "id"=>"1"} permitted: false>
[2] pry(#<PostsController>)> params[:id]
=> "1"

You can get the id by writing params [: id] like this. Use this id to get one data from the Post model data.

PostsController.rb


def show
  @post = Post.find(params[:id])
end

By setting it as model .find (id number), one data that matches the id and id number of the model is acquired. Next is show.slim.

show.slim


.container
  .card.my-4
    .card-header
      = @post.title
    .card-body
      p.card-text
        = @post.content

A screen like this will be displayed when the transition occurs. スクリーンショット 2020-08-15 16.39.02.png

8. edit action definition, edit form creation

First, set up the edit button in the same way as the detail button.

index.slim


.container
  h1.mt-4 Posts#index
  = link_to 'sign up', new_post_path

  - @posts.each do |post|
    .card.my-4
      .card-header
        = post.title
      .card-body
        p.card-text
          = post.content
        = link_to 'Details', post_path(post), class: 'btn btn-success mr-2'
        //Postscript
        = link_to 'Edit', edit_post_path(post), class: 'btn btn-primary mr-2'

Let's take a look at the routing of the edit action.

Prefix Verb       URI Pattern               Controller#Action
edit_post GET      /posts/:id/edit(.:format)   posts#edit

Then define the edit action.

PostsController.rb


def edit
  @post = Post.find(params[:id])
end

The description is the same as the show action. Then write edit.slim.

edit.slim


.container
  h1.mt-4 Edit
  = form_with url: post_path(@post), model: @post do |form|
    .form-group
      = form.label :title, 'title'
      = form.text_field :title, class: 'form-control'
    .form-group
      = form.label :content, 'Contents'
      = form.text_area :content, class: 'form-control'
    = form.submit 'update', class: 'btn btn-primary'

The content is almost the same as new.slim, so the explanation is omitted. post_path (@post) is the same as when defined in new.slim, and this HTTP method is PATCH. Let's take a look at the routing.

Prefix Verb       URI Pattern               Controller#Action
   post GET      /posts/:id(.:format)        posts#show
        PATCH    /posts/:id(.:format)        posts#update
        PUT      /posts/:id(.:format)        posts#update

Since the HTTP method is PATCH, the action to be executed when the update button is pressed this time is the PostsController update action.

9. update action definition

Define the update action.

PostsController.rb


def update
  @post = Post.find(params[:id])
  @post.update(post_params)
  redirect_to posts_path
end

This is almost the same as the create action. The difference from the create action is whether the model is new or find.

10. destroy action definition

Finally delete the data. Set up a delete button as well as an edit button. Let's take a look at the routing of the destroy action.

Prefix Verb       URI Pattern               Controller#Action
 post GET      /posts/:id(.:format)        posts#show
       DELETE   /posts/:id(.:format)        posts#destroy

Since they are the same post_path, they are distinguished by the HTTP method. By setting method :: HTTP method, the action of the specified HTTP method in the specified path will be executed. I will actually describe it.

index.slim


.container
  h1.mt-4 Posts#index
  = link_to 'sign up', new_post_path

  - @posts.each do |post|
    .card.my-4
      .card-header
        = post.title
      .card-body
        p.card-text
          = post.content
        = link_to 'Details', post_path(post), class: 'btn btn-success mr-2'
        = link_to 'Edit', edit_post_path(post), class: 'btn btn-primary mr-2'
        //Postscript
        = link_to 'Delete', post_path(post), method: :delete, class: 'btn btn-danger'

Then define the destroy action.

PostsController.rb


def destroy
  @post = Post.find(params[:id])
  @post.destroy
  redirect_to posts_path
end

You have now implemented CRUD for one model.

Completed code

For the time being, the completed code is listed below.

Postscontroller.rb


class PostsController < ApplicationController
  def index
    @posts = Post.all
  end

  def new
    @post = Post.new
  end

  def create
    @post = Post.new(post_params)
    @post.save
    redirect_to posts_path
  end

  def show
    @post = Post.find(params[:id])
  end

  def edit
    @post = Post.find(params[:id])
  end

  def update
    @post = Post.find(params[:id])
    @post.update(post_params)
    redirect_to posts_path
  end

  def destroy
    @post = Post.find(params[:id])
    @post.destroy
    redirect_to posts_path
  end

  private

  def post_params
    params.require(:post).permit(:title, :content)
  end
end

in conclusion

For the time being, I was able to write all the content I wanted to show to myself a year ago.

Recommended Posts

[Ruby on Rails] 1 model CRUD (Routing Main)
Ruby On Rails devise routing conflict
[Ruby on Rails] model, controller terminal command
Ruby on Rails model creation / deletion command
[Ruby on Rails] Model test with RSpec
Ruby on Rails Elementary
Ruby on Rails basics
Ruby On Rails Association
Ruby on rails learning record -2020.10.03
Portfolio creation Ruby on Rails
Ruby on rails learning record -2020.10.04
[Ruby on Rails] Debug (binding.pry)
Ruby on rails learning record -2020.10.05
Ruby on rails learning record -2020.10.09
Ruby on Rails config configuration
Ruby on Rails basic learning ①
[Ruby on Rails] about has_secure_password
Ruby on rails learning record-2020.10.07 ②
Commentary on partial! --Ruby on Rails
Ruby on rails learning record-2020.10.07 ①
Cancel Ruby on Rails migration
Ruby on rails learning record -2020.10.06
Ruby on Rails validation summary
[Ruby on Rails] Search function (model, method selection formula)
Ruby on Rails Basic Memorandum
[Ruby on Rails] Elimination of Fat Controller-First, logic to model-
[Ruby on Rails] Read try (: [],: key)
[Ruby on Rails] yarn install --check-files
Ruby on Rails variable, constant summary
Installing Ruby + Rails on Ubuntu 18.04 (rbenv)
Basic knowledge of Ruby on Rails
Progate Ruby on Rails5 Looking Back
How to use Ruby on Rails
[Ruby on Rails] Add / Remove Columns
Ruby on Rails Japanese-English support i18n
(Ruby on Rails6) "Erase" posted content
[Ruby on Rails] CSV output function
Ruby on Rails 6.0 environment construction memo
[Ruby on Rails] What is Bcrypt?
[Ruby on Rails] Confirmation page creation
[Ruby on Rails] Comment function implementation
[Ruby on Rails] DM, chat function
[Ruby on Rails] Convenient helper method
[Ruby on Rails] Stop "looping until ..."
[Ruby on Rails] Introduction of initial data
[Ruby on Rails] Search function (not selected)
[Rails] Addition of Ruby On Rails comment function
[Ruby on Rails] Creating an inquiry form
Ruby on Rails6 Practical Guide cp13 ~ cp15 [Memo]
[Ruby on Rails] View test with RSpec
[Ruby on Rails] How to use CarrierWave
[Ruby on Rails] Code check using Rubocop-airbnb
Ruby on Rails installation method [Mac edition]
Let's summarize "MVC" of Ruby on Rails
[Ruby on Rails] About bundler (for beginners)
part of the syntax of ruby ​​on rails
Ruby on Rails6 Practical Guide cp7 ~ cp9 [Memo]
Ruby on Rails in Visual Studio Codespaces
[Ruby on Rails] Follow function implementation: Bidirectional
Notes on using FCM with Ruby on Rails
[Ruby on Rails] Controller test with RSpec