如何在Rails表单中具有下拉<select>字段?


77

我正在创建一个脚手架-

rails g scaffold Contact email:string email_provider:string 

但我希望电子邮件提供商是下拉列表(使用gmail / yahoo / msn作为选项),而不是文本字段。我怎样才能做到这一点 ?

Answers:


89

您可以看一下Rails文档。无论如何,以您的形式:

  <%= f.collection_select :provider_id, Provider.order(:name),:id,:name, include_blank: true %>

如您所料,您应该在另一个模型中预定义电子邮件提供者- Provider,以便在哪里选择它们。


所以模型将是contact.rb,但是我应该在哪里放置下拉逻辑?抱歉,您天真的问题,我是RoR开发的
新手

1
您的问题还好。如果您查看一下自己的结构app/views/contacts,就会找到一个文件_form.html.erb。您可以尝试将其放置在此处。该“局部视图”负责创建和更新您生成的支架的动作。
R Milushev 2013年

3
建议将order(:name)移动到模型中的范围(方法)。在这里这没什么大不了的,但是随着时间的流逝,您会发现在视图模板上拥有这样的本质(排序)业务逻辑变得一团糟。将其移至控制器,或者理想情况下,将其移至控制器,并在此处提供一个可以使用的示波器。一个示例-如果最终得到三个使用下拉菜单的屏幕或模板,则视图中的顺序意味着3倍重复。将其包含在模型中意味着将它定义在一个地方,这是唯一可以更改它的地方。
Michael Durrant 2014年

52

或用于自定义选项

<%= f.select :desired_attribute, ['option1', 'option2']%>

6
<%= f.select:desired_attribute,options_for_select([['opt1'],['opt2']])这对我
有用

16

您在Contact控制器中创建集合-

app/controllers/contacts_controller.erb 

新增中

@providers = Provider.all.by_name

新,创建和编辑方法,使用范围为by_nameProvider模型- app/models/provider.rb-按名称排序

scope by_name  order(:name)

然后在视图中app/views/contacts/_form.html.erb--您使用

<%= f.collection_select :provider_id, @providers, :id, :name, include_blank: true %>

对于Rails表单,我也强烈建议您看一下诸如simple_form- https : //github.com/plataformatec/simple_form之类的表单构建器,它将完成所有繁重的工作。


谢谢Michael,我编辑了问题,并输入了另一个对我有用的代码,所以想知道使用下面的答案中提到的Select和collection_select有什么区别吗?
iCyborg

9

这是一个很长的路要走,但是如果您尚未实现,则可以最初以这种方式创建模型。下面的方法描述了更改现有数据库。

1)为电子邮件提供商创建一个新模型:
$ rails g model provider name

2)这将使用名称字符串和时间戳创建您的模型。它还创建了我们需要添加到架构的迁移:
$ rake db:migrate

3)添加一个迁移以将提供商ID添加到联系人中:
$ rails g migration AddProviderRefToContacts provider:references

4)在迁移文件上检查其外观是否正常,然后进行迁移:
$ rake db:migrate

5)好吧,现在我们有了provider_id,我们不再需要原始的email_provider字符串:
$ rails g migration RemoveEmailProviderFromContacts

6)在迁移文件中,添加如下所示的更改:

class RemoveEmailProviderFromContacts < ActiveRecord::Migration
  def change
    remove_column :contacts, :email_provider
  end
end

7)完成后,迁移更改:
$ rake db:migrate

8)让我们花点时间来更新我们的模型:
联系人:belongs_to :provider
提供者:has_many :contacts

9)然后,我们在视图的_form.html.erb部分中设置下拉逻辑:

  <div class="field">
    <%= f.label :provider %><br>
    <%= f.collection_select :provider_id, Provider.all, :id, :name %>
  </div>

10)最后,我们需要添加提供者自己。一种最有效的方法是使用种子文件:

Provider.destroy_all

gmail = Provider.create!(name: "gmail")
yahoo = Provider.create!(name: "yahoo")
msn = Provider.create!(name: "msn")

$ rake db:seed


6

<%= f.select :email_provider, ["gmail","yahoo","msn"]%>


5

在这里看看

您可以使用rails标记,也可以使用纯HTML标记

Rails标签

<%= select("Contact", "email_provider", Contact::PROVIDERS, {:include_blank => true}) %>

*以上代码行将变为HTML代码(HTML标记),请在下面找到*

HTML标签

<select name="Contact[email_provider]">
  <option></option>
  <option>yahoo</option>
  <option>gmail</option>
  <option>msn</option>
</select>

谢谢,我还是很困惑,我理解<select>代码会放在_form.html.erb中,但是select(“ Contact”,)代码会去哪里?
iCyborg

3

在您的模型中

class Contact
  self.email_providers = %w[Gmail Yahoo MSN]
  validates :email_provider, :inclusion => email_providers
end

以您的形式,

<%= f.select :email_provider, 
    options_for_select(Contact.email_providers, @contact.email_provider) %>

options_for_select的第二个参数将选择任何当前的email_provider。


2

Rails使用has_many关联的文章和类别进行下拉:

has_many :articles

belongs_to :category

<%= form.select :category_id,Category.all.pluck(:name,:id),{prompt:'select'},{class: "form-control"}%>
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.