如何在Rails中自定义表单/ POST?

时间:2011-03-05 16:28:11

标签: ruby-on-rails ruby-on-rails-3 validation forms post

嘿伙计们,这一直困扰着我。我是Rails的新手,所以请温柔:)

我的根本问题是我正在尝试编写一个form_for Post,它将在输入上使用自动完成功能将帖子绑定到客户端。数据库正在查找client_id,而不是文本名称。 所以我尝试了一个自定义验证,它将查找文本值并用id替换它。 我的Post.rb文件包含:

class Post < ActiveRecord::Base
    belongs_to :client
    attr_accessor :client_name
    attr_accessible :client_name
    before_validation_on_create :validate_client

    def validate_client
        self.client_id = 1 # just a test
    end

    def client_exists(passed_name)
      return Client.where(:full_name => passed_name).first.blank?
    end
end

但是当我这样做时,没有任何表单变量被传递。数据库获取除client_id之外的所有空白条目。如何实现此目的?为什么我的表单变量没有传入?非常感谢提前。

编辑1:从posts_controller.rb添加了创建定义

def create
    @post = Post.new(params[:post])

    respond_to do |format|
      if @post.save
        format.html { 
            redirect_to(posts_url) # redirect_to(@post, :notice => 'Post was successfully created.')        
        }
        format.xml  { render :xml => @post, :status => :created, :location => @post }
        format.js
      else
        format.html { render :action => "new" }
        format.xml  { render :xml => @post.errors, :status => :unprocessable_entity }
      end
    end
  end

编辑2:感谢@apneadiving,我更改了attr_accesible以包含其他属性,并将POST条目传递到db。

attr_accessible :client_id, :time, :content, :client_name

但是当我更改validate_client函数以搜索client_id时,

def validate_client
    passed_name = self.client_name

    if client_exists(passed_name)
        c = Client.where(:full_name => passed_name).first
        self.client_id = c.id
    else
        errors.add_to_base "Error"
    end
end

它总是给我这个错误:

  

为nil调用id,这会   错误地是4 - 如果你真的   想要id为nil,请使用object_id

编辑3:这是我的帖子表格。我无法正确获取:client_name的值。

<%= form_for(@post) do |f| %>
  <%= render 'common/error_messages', :object => f.object %>
  <div class="field">
      <%= f.label :content %><br />
      <%= f.text_area :content, :size => "50x6" %>
    </div>
  <div class="field">
    <div class="sub-field">
      <%= f.label :client_name %><br />
      <%= f.text_field :client_name, :size => "26" %>
    </div>
    <div class="sub-field">
      <%= f.label :date %><br />
      <%= f.text_field(:time, :class => 'date', :size => "10", :value => Date.today.strftime('%m/%d/%Y')) %>
    </div>
    <div class="sub-field">
      <%= f.label :time %><br />
      <%= f.time_select :time %>
    </div>
  </div>

  <div class="actions clear">
    <%= f.submit %>
  </div>
<% end %>

编辑4:解决方案。我很难得到:client_name,因为我的文字太过标签了(我最初将函数私有化,然后把“私有”这个词拿出来) 。修改后的@ apneadiving的答案为我解决了这个问题!

class Post < ActiveRecord::Base
    belongs_to :client
    attr_accessor :client_name
    validate :validate_client

    def validate_client
        passed_name = self.client_name

        unless client = Client.find_by_full_name(passed_name).blank?
          self.client_id = Client.find_by_full_name(passed_name).id
        else
          errors.add(:client_name, "'#{passed_name}' cannot be found.")
        end
    end

end

2 个答案:

答案 0 :(得分:1)

小心您的attr_acessible

如果你设置了一个,你必须设置所有可以通过参数设置的变量。否则,他们会受到mass assignment

的保护

编辑1:

似乎c.id为零,这意味着您的client_exists函数无法正常工作。尝试以下(未经测试):

def validate_client
  unless client = Client.find_by_full_name(client_name).nil?
    client_id = client.id
  else
    errors.add_to_base "Error"
  end
end

答案 1 :(得分:0)

您的client_exists代码错误,如果不存在则返回true。 此外,由于您的client_existsvalidation重复使用相同的查询,我会稍微重写一下。

def validate_client
  passed_name = self.client_name

  existing_client = Client.where(:full_name => passed_name).first
  if existing_client
    self.client_id = existing_client.id
  else
    errors.add_to_base "Error"
  end
end