markdown Rails中的多态性

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了markdown Rails中的多态性相关的知识,希望对你有一定的参考价值。

### Polymorphism in Rails

---

* Allows you to have a model **associated with more than one other model without the use of a join table**
* How?
    * Adding a **type** and **id** field to the table of the model you wish to make polymorphic
    * When creating the association using `rails g` and appending **name:references{polymorphic}** 
    can be used to quickly establish the `_type` and `_id` polymorphic column names (all done by Rails).
* Convention is to '-able' to the polymorphic attribute.

---

#### Example: Person, Business & Interaction

* Interactive will belong to an Interaction which Person and Business will have many of:

```ruby
rails g model Person first_name last_name 
rails g model Business name
rails g model Interaction description interactive:references{polymorphic}
# you can use any name for the polymorphic id and type, just as long as they make sense

rake db:migrate
```

* Add to Person and Business class (keep Interaction class the same)

```ruby
class Person < ApplicationRecord
   has_many :interactions, as: :interactive
end

class Business < ApplicationRecord
   has_many :interactions, as: :interactive
end

# This should defaulted by rails
class Interaction < ApplicationRecord
   belongs_to :interactive, polymorphic: true
end
```

* If you open `rails c` and then entered `Interaction.column_names`, you will see:
    * `interaction_id`: holds the **id** of the model that the interaction belongs to
    * `interaction_type`: holds the **type** of the model that the interaction belongs to
    * Both tell Rails which model this interaction should be associated with
* Adding the following controllers:

```ruby 
# in terminal
rails g controller People index show new create edit update
rails g controller Businesses index show new create edit update
rails g controller Interactions new create edit update
```

* **Nest your resources** such that the polymorphic association is nested within each model!
* You will need some way to **parse** which object the polymorphic association belongs to:
    * Checking the **params** for the object's class and then **returning** the object in the db

```ruby
class InteractionsController < ApplicationController
  def new
  	@context = context
  	@interaction = @context.interactions.new
  end

  def create
  	@context = context
  	@interaction = @context.interactions.new(interaction_params)

  	if @interactions.save
  		redirect_to context_url(@context), notice: "The interaction has been successfully created."
  	end
  end

  def edit
  	@context = context
  	@interaction = @context.interactions.find(params[:id])
  end

  def update
  	@context = context 
  	@interaction = @context.interactions.find(params[:id])

  	if @interaction.update_attributes(interaction_params)
  		redirect_to context_url(@context), notice: "The interaction has been successfully updated."
  	end
  end

  private

  def interaction_params
  	params.require(:interaction).permit!
  end

  def context
  	if params[:person_id]
  		id = params[:person_id]
  		Person.find(params[:person_id])
  	else
  		id = params[:business_id]
  		Business.find(params[:business_id])
  	end
  	
  end

  def context_url(context)
  	if Person === context
  		person_path(context)
  	else
  		business_path(context)
  	end
  end

end
```

* For your forms that use the polymorphic association:

```ruby
<%= form_for [obj1, obj2] do %>
   #...
<% end %>
```

* `obj1` is the object returned from parsing the polymorphic association (ex. @context = context)
* `obj2` is the object of the polymorphic class (ex. Interaction.new)

---

# Checking in Rails Console
* Seed the database with Person and Business objects.
* In `rails console`:

```ruby
p = Person.first
p.interactions.build(description: "asdfgh asdf").save
p.interactions.first.interactive_type 
# returns "Person"
p.interactions.first.interactive_id 
# returns the corresponding id of the Person object

# Now that you have an interaction, you can call the method interactive on the Interaction object to retrieve
# it's parent:
i = Interaction.first
i.interactive # returns the corresponding parent object (Person in this case)
```

* You build the polymorphic relationship by calling **build** on the model that has_many of the polymorphic
association.
* You'll then have access to the id and type of the object!

以上是关于markdown Rails中的多态性的主要内容,如果未能解决你的问题,请参考以下文章

markdown Rails中的分页

markdown 如何解决Rails(OSX)中的OpenSSL错误?

markdown Rails任务(Ruby中的学生注册).md

Ruby on Rails: :include 与子模型的多态关联

对嵌套注释使用 Rails 多态性

Rails 5 - 使用多态关联 - 渲染视图