2

「published_at」という日時フィールドを持つ投稿モデルがあります。私のフォームには、「publish_now」という名前の属性のチェックボックスがあります (以下を参照)。ユーザーが仮想属性 :publish_now のチェックボックスをオンにしたときに、"published_at" を Time.now() に設定したい。

<input class="boolean optional" id="post_publish_now" name="post[publish_now]" type="checkbox" value="1" />

コントローラーの作成および更新メソッドは次のとおりです。

def create
  @post = Post.new(params[:post])
  if current_user
    @post.author_id == current_user.id
  end

  respond_to do |format|
    if @post.save
      format.html { redirect_to @post, notice: 'Post was successfully created.' }
      format.json { render json: @post, status: :created, location: @post }
    else
      format.html { render action: "new" }
      format.json { render json: @post.errors, status: :unprocessable_entity }
    end
  end
end

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

  respond_to do |format|
    if @post.update_attributes(params[:post])
      format.html { redirect_to @post, notice: 'Post was successfully updated.' }
      format.json { head :no_content }
    else
      format.html { render action: "edit" }
      format.json { render json: @post.errors, status: :unprocessable_entity }
    end
  end
end

そして、ここに私のモデルがあります:

class Post < ActiveRecord::Base
  belongs_to :author, class_name: "User", foreign_key: "author_id"

  attr_accessible :author_id, :content, :published_at, :title, :publish_now

  validates_presence_of :content, :title

  def publish_now
    !published_at.nil?
  end

  def publish_now=(value)
    if value == "1" && published_at.nil?
      published_at = Time.now()
    end 
  end
end

これは、仮想属性の railscast に基づいてどのように機能するかについての私の最善の推測ですが、published_at の値を保存していません。問題が発生している可能性のある提案はありますか?

更新: (フォーム ビュー)

<%= simple_form_for(@post) do |f| %>
  <%= f.input :title %>
  <%= f.input :content, input_html: { cols: 100, rows: 10, class: "
    span5" } %>
  <% if @post.published_now == false %>
    <%= f.input :publish_now, as: :boolean %>
  <% end %>
  <%= f.submit %>
<% end %>

更新ログの例:

Started POST "/posts" for 127.0.0.1 at 2012-10-31 14:14:49 -0500
Processing by PostsController#create as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"zlZ3s18VXwEvONIkk1CZAYESAEAxPP1OKcUtiyEuZgA=", "post"=>{"title"=>"big big love a doodle", "content"=>"aksdfj;skjf;kasjdf; lkj af;lk ;askdfj ;lk ;laf; ksd ;f", "publish_now"=>"1"}, "commit"=>"Create Post"}
  User Load (0.8ms)  SELECT "users".* FROM "users" WHERE "users"."id" = 1 LIMIT 1
   (0.2ms)  BEGIN
  SQL (0.7ms)  INSERT INTO "posts" ("author_id", "content", "created_at", "published_at", "title", "updated_at") VALUES ($1, $2, $3, $4, $5, $6) RETURNING "id"  [["author_id", nil], ["content", "aksdfj;skjf;kasjdf; lkj af;lk ;askdfj ;lk ;laf; ksd ;f"], ["created_at", Wed, 31 Oct 2012 14:14:49 CDT -05:00], ["published_at", nil], ["title", "big big love a doodle"], ["updated_at", Wed, 31 Oct 2012 14:14:49 CDT -05:00]]
   (0.4ms)  COMMIT
Redirected to http://localhost:3000/posts/5
Completed 302 Found in 18ms (ActiveRecord: 2.1ms)
4

1 に答える 1

3

エラーはこの行にあります

published_at = Time.now()

そのはず

self.published_at = Time.now()

括弧もオプションです。何かに代入すると、オブジェクトを明示的に提供しない限り、Ruby はそれがローカル変数であると見なします。そうして初めて、Ruby はそれが実際に呼び出したいメソッド (published_at= メソッド) であることを知ることができます。これは、Ruby でよくある落とし穴です。

コードでは、新しいローカル変数 published_at が作成されます。詳細については、「Using Accessors Within a Class」のhttp://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.htmlを参照してください。

ただし、そのような属性を読み取る場合は、自分自身をプレフィックスにする必要はありません。Ruby は、割り当てられるまで何かがローカル変数であると想定しないためです。したがって、published_at=... の前では、Ruby は published_at をメソッド呼び出しとして扱い、published_at=... を実行した後 (self を前に付けない)、published_at をローカル変数として扱います。その場合にのみ、ローカル変数を読み取る代わりに、self.published_at を使用して実際にメソッドを呼び出す必要があります。属性ライター (= で終わる) の場合、常にオブジェクトのプレフィックスを付ける必要があります。代わりに、属性ハッシュを使用することもできます。そうすれば、自分自身でプレフィックスを付ける必要がなくなります。

attributes["published_at"] = whatever
于 2012-10-31T19:51:00.897 に答える