[RUBY] (Giri) A local government employee in his twenties works on a Rails tutorial [Chapter 13]

Premise

・ Rails tutorial is the 4th edition ・ This study is the 3rd lap (2nd lap after Chapter 9) ・ The author is a beginner who has done all of Progate.

Basic policy

・ If you read it, you will not understand it. ・ Search and summarize terms that you do not understand (at the bottom of the article, glossary). ・ Dive into what you do not understand. ・ Work on all exercises. ・ Do not copy chords as much as possible.

Well, Chapter 13. There are only two chapters left at the earliest. This time, we will implement a user message posting function called Micro Post. In short, it's Twitter. Let's be brave! !!   Click here for today's BGM. ARIA vocal collection I wonder if the time will come when you can work remotely while drinking a latte in Neo Venice ...

[13.1.1 Micropost model exercise]

  1. Execute Micropost.new on the Rails console and assign the instance to the variable micropost. Then try substituting the id of the first user for user_id and "Lorem ipsum" for content. What's in the magic columns (created_at and updated_at) of the micropost object at this point?

  2. The named route in Table 12.1 states that _url should be used instead of _path. Why? Think about it. Tip: For the same reason as the account activation exercise (11.1.1.1).

  3. Let's save the micropost object created earlier in the database. Magic column again at this point → Collectively don

>> micropost = Micropost.new(user_id: 1, content: "Lorem ipsum")
=> #<Micropost id: nil, content: "Lorem ipsum", user_id: 1, created_at: nil, updated_at: nil>
>> micropost.created_at
=> nil
>> micropost.updated_at
=> nil

>> micropost.user
  User Load (0.2ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
=> #<User id: 1, name: "Example User", email: "[email protected]", created_at: "2020-09-17 08:34:09", updated_at: "2020-09-17 08:34:09", password_digest: "$2a$10$.EZN.AXBx91cG82BFOaKp.qpuwRpmG5N1JASh6KIBnv...", remember_digest: nil, admin: true, activation_digest: "$2a$10$mQpfXtRYM2s5JyNF243gYOln7RRrGaHHlilpOHouLfk...", activated: true, activated_at: "2020-09-17 08:34:09", reset_digest: nil, reset_sent_at: nil>
>> micropost.user.name
=> "Example User"

>> micropost.save
   (0.1ms)  SAVEPOINT active_record_1
  SQL (1.3ms)  INSERT INTO "microposts" ("content", "user_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["content", "Lorem ipsum"], ["user_id", 1], ["created_at", "2020-09-21 02:33:40.343372"], ["updated_at", "2020-09-21 02:33:40.343372"]]
   (0.1ms)  RELEASE SAVEPOINT active_record_1
=> true
>> micropost.created_at
=> Mon, 21 Sep 2020 02:33:40 UTC +00:00
>> micropost.updated_at
=> Mon, 21 Sep 2020 02:33:40 UTC +00:00

[13.1.2 Micropost validation exercise]

  1. Open the Rails console and create a micropost object with empty user_id and content. Let's make sure that running valid? On this object fails. Also, what is written in the generated error message? → Below
>> micropost = Micropost.new(user_id: " ", content: " ")
=> #<Micropost id: nil, content: " ", user_id: nil, created_at: nil, updated_at: nil>
>> micropost.valid?
=> false
>> micropost.errors.messages
=> {:user=>["must exist"], :user_id=>["can't be blank"], :content=>["can't be blank"]}

2. Open the console and try creating a micropost object with an empty user_id and a content of 141 characters or more. Let's make sure that running valid? On this object fails. Also, what is written in the generated error message? → Below

>> micropost = Micropost.new(user_id: " ", content: "a" * 141)
=> #<Micropost id: nil, content: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...", user_id: nil, created_at: nil, updated_at: nil>
>> micropost.valid?=> false
>> micropost.errors.messages=> {:user=>["must exist"], :user_id=>["can't be blank"], :content=>["is too long (maximum is 140 characters)"]}

[13.1.3 User / Micropost association memos and exercises]

belongs_to: to belongs to the following. The side that sets this can be used as a method. has_many: Set on the side that becomes the parent with the tie.

  1. Assign the first user in the database to the variable user. What are the results of running micropost = user.microposts.create (content: "Lorem ipsum") with that user object? → Below
>> user = User.first
  User Load (0.1ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
=> #<User id: 1, name: "Example User", email: "[email protected]", created_at: "2020-09-17 08:34:09", updated_at: "2020-09-17 08:34:09", password_digest: "$2a$10$.EZN.AXBx91cG82BFOaKp.qpuwRpmG5N1JASh6KIBnv...", remember_digest: nil, admin: true, activation_digest: "$2a$10$mQpfXtRYM2s5JyNF243gYOln7RRrGaHHlilpOHouLfk...", activated: true, activated_at: "2020-09-17 08:34:09", reset_digest: nil, reset_sent_at: nil>
>> micropost = user.microposts.create(content: "Lorem ipsum")                       
   (0.1ms)  SAVEPOINT active_record_1
  SQL (1.8ms)  INSERT INTO "microposts" ("content", "user_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["content", "Lorem ipsum"], ["user_id", 1], ["created_at", "2020-09-21 03:35:41.329488"], ["updated_at", "2020-09-21 03:35:41.329488"]]
   (0.1ms)  RELEASE SAVEPOINT active_record_1
=> #<Micropost id: 1, content: "Lorem ipsum", user_id: 1, created_at: "2020-09-21 03:35:41", updated_at: "2020-09-21 03:35:41">

2. A new micropost should have been added to the database in the previous exercise. Run user.microposts.find (micropost.id) to see if it was really added. Also, what will happen if you change the micropost.id part you just executed to micropost? → Below

>> user.microposts.find(micropost.id)
  Micropost Load (0.2ms)  SELECT  "microposts".* FROM "microposts" WHERE "microposts"."user_id" = ? AND "microposts"."id" = ? LIMIT ?  [["user_id", 1], ["id", 1], ["LIMIT", 1]]
=> #<Micropost id: 1, content: "Lorem ipsum", user_id: 1, created_at: "2020-09-21 03:35:41", updated_at: "2020-09-21 03:35:41">
>> user.microposts.find(micropost)
Traceback (most recent call last):
        1: from (irb):6
ArgumentError (You are passing an instance of ActiveRecord::Base to `find`. Please pass the id of the object by calling `.id`.)

3. What will happen to the result of executing user == micropost.user? Also, what will happen to the result of executing user.microposts.first == micropost? Please check each. → Below

>> user == micropost.user
=> true
>> user.microposts.first == micropost
  Micropost Load (0.2ms)  SELECT  "microposts".* FROM "microposts" WHERE "microposts"."user_id" = ? ORDER BY "microposts"."id" ASC LIMIT ?  [["user_id", 1], ["LIMIT", 1]]
=> true

[13.1.4 Notes and exercises to improve the micro post]

default_scope: Used when you want to apply a scope to all queries in the model. dependent:: destroy: set to has_many. When the parent is deleted, all associated child databases are deleted. In addition, various things have appeared, so I have summarized them in a glossary.

  1. Let's compare the execution result of Micropost.first.created_at with the execution result of Micropost.last.created_at. → After making two microposts appropriately, the following (Because I am using sandbox somehow, the previous exercise data does not remain)
>> Micropost.first.created_at
  Micropost Load (0.1ms)  SELECT  "microposts".* FROM "microposts" ORDER BY "microposts"."created_at" DESC LIMIT ?  [["LIMIT", 1]]
=> Mon, 21 Sep 2020 04:56:04 UTC +00:00
>> Micropost.last.created_at
  Micropost Load (0.2ms)  SELECT  "microposts".* FROM "microposts" ORDER BY "microposts"."created_at" ASC LIMIT ?  [["LIMIT", 1]]
=> Mon, 21 Sep 2020 04:55:35 UTC +00:00

2. What happens to the SQL statement issued when Micropost.first is executed? Similarly, what happens to Micropost.last? Hint: When each is executed on the console The character string displayed in is the SQL statement. → Below

>> Micropost.first
  Micropost Load (0.2ms)  SELECT  "microposts".* FROM "microposts" ORDER BY "microposts"."created_at" DESC LIMIT ?  [["LIMIT", 1]]
=> #<Micropost id: 2, content: "jaoivhiua", user_id: 2, created_at: "2020-09-21 04:56:04", updated_at: "2020-09-21 04:56:04">
>> Micropost.last
  Micropost Load (0.1ms)  SELECT  "microposts".* FROM "microposts" ORDER BY "microposts"."created_at" ASC LIMIT ?  [["LIMIT", 1]]
=> #<Micropost id: 1, content: "krutinb", user_id: 1, created_at: "2020-09-21 04:55:35", updated_at: "2020-09-21 04:55:35">

3. Assign the first user on the database to the variable user. What is the id of the micropost that the user object first posted? Next, try deleting the user object using the destroy method. If you delete it, let's check in Micropost.find that the micropost associated with that user is also deleted. → Below

>> user = User.first
  User Load (0.1ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
=> #<User id: 1, name: "Example User", email: "[email protected]", created_at: "2020-09-17 08:34:09", updated_at: "2020-09-17 08:34:09", password_digest: "$2a$10$.EZN.AXBx91cG82BFOaKp.qpuwRpmG5N1JASh6KIBnv...", remember_digest: nil, admin: true, activation_digest: "$2a$10$mQpfXtRYM2s5JyNF243gYOln7RRrGaHHlilpOHouLfk...", activated: true, activated_at: "2020-09-17 08:34:09", reset_digest: nil, reset_sent_at: nil>

>> user.microposts.first.id
  Micropost Load (0.2ms)  SELECT  "microposts".* FROM "microposts" WHERE "microposts"."user_id" = ? ORDER BY "microposts"."created_at" DESC LIMIT ?  [["user_id", 1], ["LIMIT", 1]]
=> 1

>> user.destroy
   (0.1ms)  SAVEPOINT active_record_1
  Micropost Load (0.1ms)  SELECT "microposts".* FROM "microposts" WHERE "microposts"."user_id" = ? ORDER BY "microposts"."created_at" DESC  [["user_id", 1]]
  SQL (0.1ms)  DELETE FROM "microposts" WHERE "microposts"."id" = ?  [["id", 1]]
  SQL (0.7ms)  DELETE FROM "users" WHERE "users"."id" = ?  [["id", 1]]
   (0.1ms)  RELEASE SAVEPOINT active_record_1
=> #<User id: 1, name: "Example User", email: "[email protected]", created_at: "2020-09-17 08:34:09", updated_at: "2020-09-17 08:34:09", password_digest: "$2a$10$.EZN.AXBx91cG82BFOaKp.qpuwRpmG5N1JASh6KIBnv...", remember_digest: nil, admin: true, activation_digest: "$2a$10$mQpfXtRYM2s5JyNF243gYOln7RRrGaHHlilpOHouLfk...", activated: true, activated_at: "2020-09-17 08:34:09", reset_digest: nil, reset_sent_at: nil>

>> Micropost.find(1)
  Micropost Load (0.2ms)  SELECT  "microposts".* FROM "microposts" WHERE "microposts"."id" = ? ORDER BY "microposts"."created_at" DESC LIMIT ?  [["id", 1], ["LIMIT", 1]]
Traceback (most recent call last):
        1: from (irb):13
ActiveRecord::RecordNotFound (Couldn't find Micropost with 'id'=1)

[13.2.1 Micropost drawing exercise]

  1. As briefly explained in 7.3.3, the time_ago_in_words method used as the helper method this time can be called from the helper object of the Rails console. Let's execute 3.weeks.ago and 6.months.ago using the time_ago_in_words method of this helper object.

  2. What kind of result will be returned when you execute helper.time_ago_in_words (1.year.ago)? → Collectively below

>> helper.time_ago_in_words(3.weeks.ago)
=> "21 days"
>> helper.time_ago_in_words(6.months.ago)
=> "6 months"
>> helper.time_ago_in_words(1.year.ago)
=> "about 1 year"

3. What is the class of the microposts object? Hint: As you can see in the code in Listing 13.23, first get the object with the paginate method (argument is page: nil) and then call the class method. → Below

s' for #<Class:0x0000000005968db8>)
>> user = User.first
  User Load (0.2ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
=> #<User id: 1, name: "Example User", email: "[email protected]", created_at: "2020-09-17 08:34:09", updated_at: "2020-09-17 08:34:09", password_digest: "$2a$10$.EZN.AXBx91cG82BFOaKp.qpuwRpmG5N1JASh6KIBnv...", remember_digest: nil, admin: true, activation_digest: "$2a$10$mQpfXtRYM2s5JyNF243gYOln7RRrGaHHlilpOHouLfk...", activated: true, activated_at: "2020-09-17 08:34:09", reset_digest: nil, reset_sent_at: nil>
>> microposts = user.microposts.paginate(page: nil)
  Micropost Load (0.1ms)  SELECT  "microposts".* FROM "microposts" WHERE "microposts"."user_id" = ? ORDER BY "microposts"."created_at" DESC LIMIT ? OFFSET ?  [["user_id", 1], ["LIMIT", 11], ["OFFSET", 0]]
=> #<ActiveRecord::AssociationRelation []>
>> microposts.class
=> Micropost::ActiveRecord_AssociationRelation

[13.2.2 Micropost sample exercise]

  1. Can you guess the execution result of the code (1..10) .to_a.take (6)? Let's actually use the console to check if the guessed values match. → You can create an array [1,2,3,4,5,6]. As expected.
>> (1..10).to_a.take(6)
=> [1, 2, 3, 4, 5, 6]

2. Do you really need the to_a method part from the previous exercise? Please check. → You can do it without it.

>> (1..10).take(6)
=> [1, 2, 3, 4, 5, 6]

3. Faker supports a wide variety of cases other than lorem ipsum. Learn how to print to the screen while looking at the Faker documentation, and actually print the university name, phone number, Hipster Ipsum and Chuck Norris facts to the screen. (Translation: Of course, it also supports Japanese, for example, there is faker-okinawa that outputs Okinawan terms. Please play with it.) → Below (If you budget faker-okinawa as it is, an error will occur, so comment out the normal faker gem before bundling.)

>> Faker::University.name
=> "East Abshire University"
>> Faker::PhoneNumber.cell_phone
=> "1-315-982-9239"
>> Faker::Hipster.sentence
=> "Mumblecore pug tilde marfa drinking 8-bit."
>> Faker::ChuckNorris.fact
=> "Chuck Norris can binary search unsorted data."

>> Faker::Okinawa::Awamori.name
=> "Mizuho"

[13.2.3 Notes and exercises to test the micro post on the profile screen]

Appeared again response.body. Contains full HTML. Find the relevant element in the HTML with assert_match. A more abstract method than assert_select. 'h1> img.gravatar' ⇨ A nest called img tag with gravatar class inside the h1 tag.

  1. Comment out the relevant application-side code to make sure the two'h1'tests in Listing 13.28 are correct. Try to see the test change from green to red. → Let's comment out the contents of h1 in the show view.

ruby:show.thml.erb


      <h1>
        <%#= gravatar_for @user %>
        <%#= @user.name %>
      </h1>

2. Let's change the test in Listing 13.28 to test that will_paginate is displayed only once. Tip: See Table 5.2. → Just add count; 1.

users_profile_test.rb


  test "profile display" do
    get user_path(@user)
    assert_template 'users/show'
    assert_select 'title', full_title(@user.name)
    assert_select 'h1', text: @user.name
    assert_select 'h1>img.gravatar'
    assert_match @user.microposts.count.to_s, response.body
    assert_select 'div.pagination', count: 1
    @user.microposts.paginate(page: 1).each do |micropost|
      assert_match micropost.content, response.body
    end
  end

[13.3.1 Micropost access control exercise]

  1. Why is it wrong to leave the logged_in_user filter in the Users controller? Think about it. → This is to eliminate duplication. It goes against the principle of DRY.

[13.3.2 Exercise to create a micro post]

  1. Let's refactor the Home page and create a partial for each branch of the if-else statement. → Is it like this?

ruby:home.thml.erb


<% if logged_in? %>
  <%= render 'logged_in' %>
<% else %>
  <%= render 'not_logged_in' %>
<% end %>

ruby:_logged_in.html.erb


  <div class="row">
    <aside class="col-md-4">
      <section class="user_info">
        <%= render 'shared/user_info' %>
      </section>
      <section class="micropost_form">
        <%= render 'shared/micropost_form' %>
      </section>
    </aside>
  </div>

ruby:_not_logged_in.html.erb


  <div class="center jumbotron">
    <h1>Welcome to the Sample App</h1>
  
    <h2>
      This is the home page for the
      <a href="https://railstutorial.jp/">Ruby on Rails Tutorial</a>
      sample application.
    </h2>
  
    <%= link_to "Sign up now!", signup_path, class: "btn btn-lg btn-primary" %>
  </div>
  
  <%= link_to image_tag("rails.png ", alt: "Rails logo"),
            'http://rubyonrails.org/' %>

[13.3.3 Feed prototype exercise]

  1. Let's actually post a micropost using the newly implemented micropost posting form. What does the INSERT statement in the Rails server log send to the database? Check it out. → INSERT INTO "microposts" ("content", "user_id", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["content", "good morning."], ["user_id", 1], ["created_at", "2020-09-22 01:20:32.232820"], ["updated_at", "2020-09-22 01:20:32.232820"]]

2. Open the console and assign the first user on the database to the user variable. Then try running Micropost.where ("user_id =?", User.id), user.microposts, and user.feed, respectively, to make sure they all have the same results. Tip: You can easily tell if the results are the same by comparing with ==. → It's all the same.

>> Micropost.where("user_id = ?", user.id) == user.microposts
  Micropost Load (0.9ms)  SELECT "microposts".* FROM "microposts" WHERE "microposts"."user_id" = ? ORDER BY "microposts"."created_at" DESC  [["user_id", 1]]
  Micropost Load (0.2ms)  SELECT "microposts".* FROM "microposts" WHERE (user_id = 1) ORDER BY "microposts"."created_at" DESC
=> true
>> Micropost.where("user_id = ?", user.id) == user.feed
=> true
>> user.microposts == user.feed
  Micropost Load (0.3ms)  SELECT "microposts".* FROM "microposts" WHERE (user_id = 1) ORDER BY "microposts"."created_at" DESC
=> true

[13.3.4 Notes and exercises to delete microposts]

request.referrer method: Returns the previous URL.

  1. Create a micropost and then delete the created micropost. Next, take a look at the Rails server log to see what the DELETE statement says. → DELETE FROM "microposts" WHERE "microposts"."id" = ? [["id", 302]] (8.3ms) commit transaction

2. redirect_to request.referrer || root_redirect url line_back(fallback_location: root_url)Let's use a browser to confirm that it works well even if it is replaced with(This method is new in Rails 5)。 → It works.

[13.3.5 Exercise to test the micro post on the feed screen]

  1. For each of the four comments shown in Listing 13.55 (such as "Invalid Send"), let's check if the test is working properly. Specifically, let's comment out the corresponding application-side code, make sure the test turns red, and then undo it to green. → Yes, GREEN.

2. Let's test the total number of microposts posted in the sidebar. At this time, also test whether the singular (micropost) and plural (microposts) are displayed correctly. Tip: Use Listing 13.57 as a guide. → Is this all right?

microposts_interface_test.rb


  test "micropost sidebar count" do
    log_in_as(@user)
    get root_path
    assert_match "#{@user.microposts.count} microposts", response.body
    other_user = users(:malory)
    log_in_as(other_user)
    get root_path
    assert_match "0 microposts", response.body
    other_user.microposts.create!(content: "A micropost")
    get root_path
    assert_match "1 micropost", response.body
  end

[13.4.1 Basic image upload exercise]

  1. Let's post a micro post with an image. Did you get an image that was too large? (Don't worry, the next 13.4.3 will fix this problem). → It was ok.

2. Test the image uploader implemented in 13.4 by referring to the template shown in Listing 13.63. To prepare for the test, first add the sample images to the fixture directory (command example: cp app / assets / images / rails.png test / fixtures /). The test added in Listing 13.63 checks the file upload on the Home page and whether the image is displayed when the post is successful. Note that the method called fixture_file_upload in the test is a special method that uploads the file defined by fixture18. Tip: To check if the picture attribute is valid, use the assigns method introduced in 11.3.3. This method will allow you to access the micropost in the create action after a successful post. → Below. The test does not become GREEN here. I can't find a part that seems to be wrong, so I checked it and solved it. Refer to this article After restarting spring, it became GREEN.

microposts_interface_test.rb


  test "micropost interface" do
    log_in_as(@user)
    get root_path
    assert_select 'div.pagination'
    assert_select 'input[type="file"]'
    #Invalid transmission
    post microposts_path, params: { micropost: { content: "" } }
    assert_select 'div#error_explanation'
    #Valid transmission
    content = "This micropost really ties the room together"
    picture = fixture_file_upload('test/fixtures/rails.png', 'image/png')
    assert_difference 'Micropost.count', 1 do
      post microposts_path, params: { micropost: { 
                                      content: content,
                                      picture: picture } }
    end
    assert assigns(:micropost).picture?
    follow_redirect!
    assert_match content, response.body
    #Delete a post
    assert_select 'a', text: 'delete'
    first_micropost = @user.microposts.paginate(page: 1).first
    assert_difference 'Micropost.count', -1 do
      delete micropost_path(first_micropost)
    end
    #Access different user profiles(Make sure there is no delete link)
    get user_path(users(:archer))
    assert_select 'a', text: 'delete', count: 0
  end

[13.4.2 Image verification exercise]

  1. What happens if I try to send an image file of 5MB or more?

  2. What happens if I try to send a file with an invalid extension? → In both cases, there is no corresponding file ... You will probably get an error.

[13.4.3 Image resizing exercise]

  1. Upload a high-resolution image and check if it has been resized. If the image is rectangular, is the resizing done well? → OK

2. If you have already added the tests in Listing 13.63, you may get a confusing error message when running the test suite at this point. Let's get rid of this error. Tip: Modify the config file in Listing 13.68 to prevent CarrierWave from resizing the image during testing. → I didn't throw an error, but I did it.

[13.4.4 Image upload exercise in production environment]

  1. Upload a high-resolution image in the production environment and check if it is properly resized. Is the rectangular image properly resized? → Yosha! I got it!

Chapter 13 Summary

・ Microposts are also resources. -Link data tables with belongs_to and has_many. The child side can be used as a method. -Changed the display order in the default scope. When I looked up an article that seemed to be careful about how to use it, it came out. -Use the dependent:: destroy option to delete the associated object and itself at the same time. -By using ActiveRecord, you rarely use raw SQL. -Implemented image upload with CarrierWave. (Is the standard Active Storage now?)

End of micro post mounting ~ ~. There was quite a lot here. Especially the test and doing itself are often reviewed, but there was a lot. Now sample_app is like that too. Now it's time to enter Chapter 14. From user follow-up to status feed implementation, it's the last spurt!

Go to Chapter 14! Click here for Chapter 12 Click here for premise and author status for learning

A glossary that somehow captures the image

・ Proc An object of a block ({} or do ~ end). Blocks are not objects, so you need to make them objects with proc. See here

・ Scope (method) A collection of specific queries. Avoid writing lengthy code over and over again by putting together things that you use many times.

・ Lambda type Anonymous function. As the name implies, it's an unnamed function.

・ SQL injection An attack method that illegally manipulates a database system by intentionally using an application security deficiency and executing an SQL statement that the application does not expect. Also, a vulnerability that enables the attack.

・ MIME (Multipurpose Internet Mail Extension) A standard that allows Internet e-mail, which can only use US-ASCII text, to handle various formats.

Recommended Posts

(Giri) A local government employee in his twenties works on a Rails tutorial [Chapter 11]
(Giri) A local government employee in his twenties works on a Rails tutorial [Chapter 1]
(Giri) A local government employee in his twenties works on a Rails tutorial [Chapter 12]
(Giri) A local government employee in his twenties works on a Rails tutorial [Chapter 3]
(Giri) A local government employee in his twenties works on a Rails tutorial [Chapter 4]
(Giri) A local government employee in his twenties works on a Rails tutorial [Chapter 8]
(Giri) A local government employee in his twenties works on a Rails tutorial [Chapter 6]
(Giri) A local government employee in his twenties works on a Rails tutorial [Chapter 13]
(Giri) A local government employee in his twenties works on a Rails tutorial [Chapter 9]
(Giri) A local government employee in his twenties works on a Rails tutorial [Chapter 10]
(Giri) A local government employee in his twenties works on a Rails tutorial [Chapter 7]
(Giri) A local government employee in his twenties works on a Rails tutorial [Chapter 2]
(Giri) A local government employee in his twenties works on a Rails tutorial [Introduction]
[Ruby on Rails Tutorial] Error in the test in Chapter 3
[Rails Tutorial Chapter 5] Create a layout
[Rails Struggle/Rails Tutorial] What you learned in Rails Tutorial Chapter 6
[Rails Struggle/Rails Tutorial] What you learned in Rails Tutorial Chapter 3
(Ruby on Rails6) Creating data in a table
[Rails tutorial] A memorandum of "Chapter 11 Account Activation"
rails tutorial Chapter 6
rails tutorial Chapter 1
rails tutorial Chapter 7
rails tutorial Chapter 5
rails tutorial Chapter 9
rails tutorial Chapter 8
[Rails Tutorial Chapter 2] What to do when you make a mistake in the column name
Rails Tutorial Chapter 5 Notes
Rails Tutorial Chapter 10 Notes
Rails Tutorial Chapter 3 Notes
Rails Tutorial Chapter 3 Learning
Rails Tutorial Memorandum (Chapter 3, 3.1)
Rails Tutorial Chapter 4 Notes
Rails Tutorial Chapter 4 Learning
Rails Tutorial Chapter 1 Learning
Rails Tutorial Chapter 2 Learning
Rails Tutorial Chapter 8 Notes
Rails Tutorial Memorandum (Chapter 3, 3.3.2)
How to display a graph in Ruby on Rails (LazyHighChart)
Apply CSS to a specific View in Ruby on Rails