将字符串转换为一对多关联外键的方法

Method for converting strings into foreign key for a one-to-many association

我有一个 rails 模型 Region 我去过的地区。 RegionLocation 模型具有一对多关联,其中包含我在该区域内访问过的特定位置。

每个区域都有一个 name 字符串列。我的路线设置为使用给定的 Region.name 来形成大多数 URLs - 例如 /:name/new_location。这是出于审美原因,因为我不想用数字 (region_id) 来组成 URL.

因此,对于我添加到区域的每个新位置,都需要分配 region_id foreign_key。现在我通过在我的 Location 中有一个 region_name 列来做到这一点。然后,我的 new 位置表单有一个字段 "Region name",用于输入字符串。

要真正将新创建的location与其region关联起来,我的locations_controller中的create方法包含一段代码如下:

# CONVERT REGION_NAME TO REGION_ID

location = Location.new
l = location.region_name.downcase
if l == "chicagoland"
  location.region_id = 3
elsif l == "roadtrip 2016"
  location.region_id = 4
#...
end

location.save
redirect_to("/regions/#{region.name}/#{location.id}")

因此,对于我创建的每个新 region,我无法添加新位置,直到我手动将其字符串名称与其 id 连接起来 - 通过向 create 方法添加新代码我的 locations_controller。因此,如果我使用 id = 28 创建一个名为 "Algonquin Provincial Park" 的新区域,我需要更新我的 locations_controller - 将 "algonquin provincial park" 连接到 28,并设置 location.region_id28 。这显然不是最优的。

有没有一种方法可以对我的 newcreate 方法进行编程,以便自动为新的 location 分配一个 foreign_key 等同于 region_id它属于 region 的一部分,而无需在每次有新的 region 时向我的 Location create 方法添加代码?

作为介绍,您尝试做的事情有时被称为 pretty urls or friendly urls。您可以自己滚动,或使用 gem。看起来你已经走上了自己的道路(我也是这样做的)。如果您的 name 字段曾经包含非 url 好友元素,那么您可能需要考虑使用 slugs。我会把它留给你自己研究。

在您的 routes.rb 中,我们假设您有:

resources :regions, param: :name do 
  resources :locations
end

哪个会给你:

    region_locations GET    /regions/:region_name/locations(.:format)                locations#index
                     POST   /regions/:region_name/locations(.:format)                locations#create
 new_region_location GET    /regions/:region_name/locations/new(.:format)            locations#new
edit_region_location GET    /regions/:region_name/locations/:id/edit(.:format)       locations#edit
     region_location GET    /regions/:region_name/locations/:id(.:format)            locations#show
                     PATCH  /regions/:region_name/locations/:id(.:format)            locations#update
                     PUT    /regions/:region_name/locations/:id(.:format)            locations#update
                     DELETE /regions/:region_name/locations/:id(.:format)            locations#destroy
             regions GET    /regions(.:format)                                       regions#index
                     POST   /regions(.:format)                                       regions#create
          new_region GET    /regions/new(.:format)                                   regions#new
         edit_region GET    /regions/:name/edit(.:format)                            regions#edit
              region GET    /regions/:name(.:format)                                 regions#show
                     PATCH  /regions/:name(.:format)                                 regions#update
                     PUT    /regions/:name(.:format)                                 regions#update
                     DELETE /regions/:name(.:format)                                 regions#destroy

我们还假设您有:

class Region < ActiveRecord::Base
  has_many :locations
end

并且:

class Location < ActiveRecord::Base
  belongs_to :region
end

然后,在 locations_controller.rb 中,执​​行如下操作:

class LocationsController < ApplicationController 

  ...

  def create
    @region = Region.find_by(name: params[:region_name])
    @location = @region.locations.new(location_params)
    if @location.save
      redirect_to region_location_path(@region.name, @location)
    else
      # do something when the location doesn't save
    end
  end

  ...

private

  def location_params
    params.require(:location).permit(:some, :location, :attributes)
  end

end