Search code examples
ruby-on-railsrubymodel-view-controller

(While studying rails tutorial)How to display user information on pages not related to the user controller


Sorry for the vague question. In addition, I am not used to English, but I will do my best to communicate clearly.

It's time to set up the server and visit the page.

ActiveRecord::RecordNotFound in StaticPagesController#diary
Couldn't find User without an ID
Extracted source (around line #9):
7
8   def diary
9    @user = User.find(params[:id])
     @micropost = current_user.microposts.build if logged_in?
    end
   end
10

Explain this mistake. I added a new page to the static page and tried to put the user's information there. I wanted to add a diary posting function.

The structure of the file is as shown in the picture. the structure of the file

In other words, I want to display user information on the diary page, but I thought I was getting an error that the user's ID could not be found.

I will put the information of the diary posting page where the error occurred.

app/views/stataic_pages/diary.html.erb

<% if logged_in? %>
  <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>
<% end %>

partials

app/views/shared/_user_info.html.erb

<%= link_to gravatar_for(current_user, size: 50), current_user %>
<h1><%= current_user.name %></h1>
<span><%= link_to "view my profile", current_user %></span>
<span><%= pluralize(current_user.microposts.count, "micropost") %></span>
app/views/shared/_micropost_info.html.erb

<%= form_with(model: @micropost) do |f| %>
  <%= render 'shared/error_messages', object: f.object %>
  <div class="field">
    <%= f.text_area :content, placeholder: "Compose new micropost..." %>
  </div>
  <%= f.submit "Post", class: "btn btn-primary" %>
<% end %>

and this is controller

app/controllers/static_pages_controller.rb

class StaticPagesController < ApplicationController
  def home
  end

  def help
  end

  def diary
    @user = User.find(params[:id])
    @micropost = current_user.microposts.build if logged_in?
  end
end

route

app/config/route.rb

Rails.application.routes.draw do
  get 'sessions/new'
  get 'users/new'
  root "static_pages#home"
  get '/help', to: "static_pages#help"
  get '/search', to: 'searchs#search'
  get '/signup', to: 'users#new'
  get    "/login",   to: "sessions#new"
  post   "/login",   to: "sessions#create"
  delete "/logout",  to: "sessions#destroy"
  get '/diary',  to: "static_pages#diary"
  resources :users
  resources :microposts,          only: [:create, :destroy]
end

What I learned in the rails tutorial is that in the process of displaying a dedicated show page after logging in, add this to the user controller,

app/controllers/user


class UsersController < ApplicationController
  before_action :logged_in_user, only: [:index, :edit, :update, :destroy]
  def show
    @user = User.find(params[:id])
    @microposts = @user.microposts.paginate(page: params[:page])
  end

  def new
    @user = User.new
  end

  def create
    @user = User.new(user_params)
    if @user.save
      reset_session
      log_in @user
      flash[:success] = "Welcome to the Sample App!"
      redirect_to @user
    else
      render 'new', status: :unprocessable_entity
    end
  end

  private

    def user_params
      params.require(:user).permit(:name, :email, :password,
                                   :password_confirmation)
    end

   
    def correct_user
      @user = User.find(params[:id])
      redirect_to(root_url, status: :see_other) unless current_user?(@user)
    end

   
    def admin_user
      redirect_to(root_url, status: :see_other) unless current_user.admin?
    end
end

It was to code something like this in the view page.

app/views/users/show.html.erb

<% provide(:title, @user.name) %>
<h1>
  <%= gravatar_for @user %>
  <%= @user.name %>
</h1>
<div class="col-md-8">
    <% if @user.microposts.any? %>
      <h3>Microposts (<%= @user.microposts.count %>)</h3>
      <ol class="microposts">
        <%= render @microposts %>
      </ol>
      <%= will_paginate @microposts %>
    <% end %>
  </div>


app/models/user.rb

class User < ApplicationRecord
    has_many :microposts, dependent: :destroy
    before_save { self.email = email.downcase }
    validates :name, presence: true, length: { maximum: 50 }
    VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
    validates :email, presence: true, length: { maximum: 255 },
                      format: { with: VALID_EMAIL_REGEX },
                      uniqueness: true
    has_secure_password
    validates :password, presence: true, length: { minimum: 6 }
end

I put this code in the diary method, just like displaying the profile on this user's show page.

@user = User.find(params[:id]) @microposts = @user.microposts.paginate(page: params[:page])

But I got the above error. Is there something wrong with the model or DB relationship? Isn't there a way to bring user information to the page that has nothing to do with the user controller? Thank you for reading this far. If you have any questions, please leave a comment.


Solution

  • The problem is really how you're looking up the resource.

    @user = User.find(params[:id]) implies that the user id is part of URI. And since your route doesn't contain a :id segment params[:id] is nil.

    But if you're displaying the "profile" of the current user you should get the user from the session:

    class StaticPagesController < ApplicationController
      # ...
      def diary
        @user = current_user
        @micropost = @user.microposts.build 
      end
    end
    

    You should also perform a check beforehand to ensure that the user is logged in.