Я правильно использую форму рельсов? - PullRequest
1 голос
/ 09 марта 2012

Я чувствую, что понятия не имею, что делаю .. У меня есть смутная идея.Я надеюсь, что до сих пор я все делал правильно.

Любой способ, которым вы можете увидеть, чтобы сделать рефакторинг, был бы очень признателен.

Одна вещь, которую я заметил, это работает неправильно - она ​​не загружаетсяправильные параметры, которые были ранее отправлены, если есть ошибка, и она отправляет на тот же URL.Кажется, что текстовые вводы загружают предыдущее значение, но переключатели выбора и переключатели сбрасываются на значения по умолчанию при каждой отправке.

ResourcesController # new

 def new
    @resource = Resource.new
    @title = "Submit Resource"
    @categories = Category.all
 end

ResourcesController # create (обратите внимание, у меня есть @categories= Category.all в обоих ... в соответствии с DRY я не уверен, куда еще он должен пойти, или он работает только при первой отправке формы.

  def create
    @title = "Submit Resource"
    @categories = Category.all

    @resource = Resource.new(params[:resource])

    category_ids = @categories.map { |c| c[1] }

    if @resource.valid? and category_ids.include? params[:category_id]
      @resource.cost = params[:cost]
      @resource.category_id = params[:category_id]
      @resource.save
      redirect_to root_url
    else
      render :action => :new
    end 
  end

Resource.rb (модель)

# == Schema Information
#
# Table name: resources
#
#  id          :integer         not null, primary key
#  upvotes     :integer         default(0)
#  downvotes   :integer         default(0)
#  url         :string(255)
#  title       :string(255)
#  cost        :integer         default(0)
#  description :text
#  flags       :integer
#  category_id :integer
#  user_id     :integer
#  created_at  :datetime        not null
#  updated_at  :datetime        not null
#

class Resource < ActiveRecord::Base

  belongs_to :category
  belongs_to :user
  has_many :favorites
  has_many :resource_tags
  has_many :tags, :through => :resource_tags

  attr_accessible :url, :title, :cost, :description, :category_id, :user_id

  # Pseudo-Enum
  COST = [:free, :paid, :both]

  url_regex = /^(?:http|https):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,6}(:[0-9]{1,5})?(\/.*)?$/ix

  validates :url,         :presence => true,
                          :format   => { :with => url_regex, 
                                         :message  => "must be valid"},
                          :uniqueness => { :case_sensitive => false,
                                           :message => "has already been submitted"}
  validates :title,       :presence => true,
                          :length   => { :within => 6..75 }
  validates :cost,        :presence => true
  validates :description, :presence => true,
                          :length   => { :within => 25..200 }
  validates :category_id, :presence => true,
                          :format   => { :with => /\d+/ }
  validates :user_id,     :presence => true,
                          :format   => { :with => /\d+/ }

  def cost
    COST[read_attribute(:cost)]
  end

  def cost=(value)
    write_attribute(:cost, COST.index(value.downcase.to_sym))
  end

  def category_id
    read_attribute(:category_id).to_i
  end

  def category_id=(value)
    write_attribute(:category_id, value.to_i)
  end

end

Мой файл просмотра для Resource # новая форма

  <div class="field">
    <%= f.label :category %>
    <%= select_tag(:category_id, options_for_select(@categories.map {|c|[c.name, c.id]})) %> 
  </div>

Последнее В: я еще не работал с полем user_id. Это будет извлечено из devise и будет связывать пользователя спредоставленный ресурс. Но как мне назначить это, не делая какой-либо ввод, например скрытый ввод. Это будет происходить за кулисами в контроллере?

Ответы [ 3 ]

1 голос
/ 09 марта 2012

К вашему последнему вопросу:

devise добавляет метод current_user, который является зарегистрированным пользователем.Поэтому, если у пользователя есть несколько ресурсов, вы можете сделать что-то вроде:

@resource = current_user.resources.new(params[:resource])

Первый вопрос:

Когда форма визуализируется, это делается на основе переменных @resource & @categories.Когда вы публикуете форму, вызывается действие create, которое создает новый @resource.Если по какой-либо причине сохранение завершается неудачно, форма перерисовывается с использованием новой переменной @resource.Проблема в том, что @ resource.category не устанавливается при повторном отображении формы.Так что вам придется сделать это до is_valid?проверьте.

 def create
    @title = "Submit Resource"
    @categories = Category.all

    @resource = Resource.new(params[:resource])
    @resource.category = Category.find(params[:category_id])

    if @resource.valid? # won't be valid if there is no category found.
      @resource.cost = params[:cost]
      @resource.save
      redirect_to root_url
    else
      render :action => :new
    end 
  end

Но настоящая проблема в вашей форме.Он должен вкладывать category_id в параметры ресурса, чтобы категория устанавливалась при выполнении Resource.new (params [: resource]).

Проверьте тело запроса POST в вашей консоли или что-то еще и посмотрите, является ли оно вложеннымв ресурсе или нет.Я не знаю точный синтаксис для этого, но если вы измените это, вы можете опустить строку @ resource.category = Category.find.

1 голос
/ 09 марта 2012

Чтобы использовать Sandip, вы можете высушить свои действия, используя before_filter

class ResourcesController < ApplicationController
  before_filter :load_categories, :only => [:show, :create]

  def new
    @resource = Resource.new
  end

  def create
    @resource = Resource.new(params[:resource])
    @resource.category = Category.find(params[:category_id])

    if @resource.valid? # won't be valid if there is no category found.
      @resource.cost = params[:cost]
      @resource.save
      redirect_to root_url
    else
      render :action => :new
    end 
  end

  private

  def load_categories
    @categories = Category.all
  end
end

также, если вы планируете придерживаться @title внутри макета вашего приложения, я бы изменил @title на ваш взгляд:

yield(:title) || 'My Site'

и на соответствующих страницах используйте:

content_for(:title) do
  Submit Resource

По умолчанию будет использоваться «Мой сайт», если не указано иное.

1 голос
/ 09 марта 2012

Похоже, есть проблема с действием создания

def create
    @title = "Submit Resource"
    @categories = Category.all

    @resource = Resource.new(params[:resource])
    if @categories.collect(&:id).include?(params[:category_id].to_i)
      @resource.category_id = params[:category_id]
    end
    @resource.user = current_user
    if @resource.valid?
      @resource.cost = params[:cost]
      @resource.save
      redirect_to root_url
    else
      render :action => :new
    end 
end

просмотр

<div class="field">
    <%= f.label :category %>
    <%= select_tag(:category_id, options_for_select(@categories.map {|c|[c.name, c.id]}, :selected => @resource.category_id)) %> 
</div>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...