I'm building my second-ever basic Ruby on Rails application and having fun doing it, but have gotten stuck at precisely the same place that gave me trouble (and was never solved) on my last effort: the PUT or PATCH request.
My application has two models: entries and users. A logged-in user should be able to edit only those entries that were originally created by that user.
CONTROLLER
[
['', '700', '-', '-', '-', '5,179.00', '-', '1,350', '4,972.25', '5,006.15', '450', '2700.00', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', ''],
['', '-', '-', '-', '-', '-', '-', '1,200', '4,710.85', '5,254.15', '150', '2800.00', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', ''],
...
]
VIEW (show.html.erb - shows a single entry and includes links allowing the logged-in user who originally authored the entry to edit or delete it)
class EntriesController < ApplicationController
# authenticate user (Devise)
before_action :authenticate_user!, :except => [:index, :show]
# set entry upon page load
before_action :set_entry, :only => [:show, :edit, :update, :destroy]
# GET request - display all entries
def index
@all_entries = Entry.all
end
# GET request - display an individual entry
def show
# nothing required here because entry identified with before_action :set_entry on line 2 above
end
# GET request - access form to create a new entry
def new
@entry = Entry.new
@user = User.find(current_user[:id])
end
# GET request - access form to update an existing entry
def edit
if @entry[:user_id] != current_user[:id]
redirect_to root_path
else
redirect_to edit_entry_path
end
end
# POST request - make a new entry/save new data into db
def create
user = current_user[:id]
Entry.create({
entry_title: params[:entry][:entry_title],
book_title: params[:entry][:book_title],
text: params[:entry][:text],
img_url: params[:entry][:img_url],
tag: params[:entry][:tag],
created_at: params[:entry][:created_at],
user_id: user
})
redirect_to entries_path
end
# PUT request - save changes to an existing entry
def update
if @entry.update(entry_params)
redirect_to entry_path
else
render :new
end
end
# DELETE request - delete an existing entry from db
def destroy
@entry.destroy
redirect_to entries_path
end
private
def set_entry
@entry = Entry.find(params[:id])
end
def entry_params
params.require(:entry).permit(:email, :text, :tag)
end
end
ROUTES.RB - At first my routes were the commented-out lines, but then I had a thought that was either madness or sudden realization - should only the GET routes lead with "get"? So that's the non-commented-out attempt you see. Somehow the app works (except for the issue at hand) both ways.
In researching I've come across routes defined using a much more elaborate syntax than that I'm using here. I've been unable to figure out whether a given way of doing things is different convention, outdated, or just inadequate to the task.
<h3>Selected Entry</h3>
<div class="row">
<div class="col-md-2"></div>
<div class="col-md-6">
<div>Entry title: <%= @entry.entry_title %></div>
<div>Book title: <%= @entry.book_title %></div>
<div>Text: <%= @entry.text %></div>
</div>
<div class="col-md-4">
<div><%= @entry.created_at.strftime("%b %d, %Y") %></div>
<div>Submitted by: <i><%= @entry.user.email %></i></div>
<div>File under: <i><%= @entry.tag %></i></div>
<% if current_user %>
<%= link_to 'Edit', @entry, :method => 'update' %>
<%= link_to 'Delete', @entry, :method => 'delete' %>
<% end %>
</div>
</div>
Thanks in advance for any insight. If additional context is needed I'm happy to provide.
Edited to add: PARTIAL (_form.html.erb)
Rails.application.routes.draw do
devise_for :users
resources :entries
# root 'entries#index'
# get '/entries' => 'entries#index'
# get '/users' => 'users#index'
# get '/entries/:id' => 'entries#show'
# get '/entries/:id' => 'entries#update'
# get '/entries/new' => 'entries#new'
# get '/entries/:id/edit' => 'entries#edit'
# get '/users/:id' => 'users#show'
# get '/about' => 'pages#index'
root 'entries#index'
get '/entries' => 'entries#index'
get '/entries/new' => 'entries#new'
post '/entries' => 'entries#create'
get '/entries/:id' => 'entries#show'
get '/entries/:id/edit' => 'entries#edit'
put '/entries/:id' => 'entries#update'
delete '/entries/:id' => 'entries#destroy'
get '/users' => 'users#index'
get '/users/:id' => 'users#show'
get '/about' => 'pages#index'
end
答案 0 :(得分:0)
:method
助手中的 link_to
是指HTML动词(获取,发布等),而命名约定的控制器方法是动作。
你需要一些东西
<%= link_to 'Edit', @entry, :method => 'put' %>
或
<%= link_to 'Edit', @entry, :action => 'update' %>
答案 1 :(得分:0)
您一眼就试着发布编辑链接。记住new / edit是get方法来呈现表单,所以只需删除链接中的方法部分即可。喜欢来自
<%= link_to 'Edit', @entry, :method => 'update' %>
到
<%= link_to 'Edit', edit_entry_path(@entry) %>
答案 2 :(得分:0)
编辑你的记录
要进入编辑表单,您应该链接到条目的编辑路径
<%= link_to 'Edit', edit_entry_path(@entry) %>
Rails表单助手会自动将表单设置为使用正确的方法PUT或PATCH提交。
答案 3 :(得分:0)
我正在构建我的第二个基本的Ruby on Rails应用程序
恭喜!在一切开始有意义之前,你至少还需要3个
要添加到现有答案中,您最好先查看resources
directive来清理路线:
#config/routes.rb
root 'entries#index'
devise_for :users
resources :entries
resources :pages, only: [:index], path_names: { index: "about" }
resources :users, only: [:index,:show]
-
登录用户应该只能编辑那些最初由该用户创建的条目。
这称为授权。
虽然人们会混淆Devise能够处理授权,但它只处理身份验证。虽然您在控制器中有一个简单的实现,但您应该查看CanCanCan
或Pundit
宝石:
#Gemfile
gem "cancancan"
#app/models/ability.rb
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # guest user (not logged in)
can :manage, Post, user_id: user.id
end
end
#app/controllers/entries_controller.rb
class EntriesController < ApplicationController
def edit
authorize! :edit, @entry
end
end
-
最后,要直接回答您的问题,您需要调用update
方法(不存在)来访问编辑视图:
<% if current_user %>
<%= link_to 'Edit', @entry, :method => 'update' %>
<%= link_to 'Delete', @entry, :method => 'delete' %>
<% end %>
你应该阅读http verbs - 这就是&#34;方法&#34;选项使用link
调用。如上所述,您在使用edit
时不需要设置GET
的方法。 Update
使用put/patch
,我稍后会解释。
实现目标的更好方法如下:
<%= link_to "Edit", edit_entry_path(@entry) if can? :edit, @entry %>
<%= link_to "Delete", @entry, method: :delete, if can? :destroy, @entry %>
以上使用CanCanCan
授权方法can?