【问题标题】:How do I pass in a nested model relationship via a form_for tag in rails如何通过rails中的form_for标签传递嵌套模型关系
【发布时间】:2016-09-20 08:18:18
【问题描述】:

我有一个Conversation 模型,它有一个initiator 和一个recipient 属性,它们都是User 模型。

创建form_for @conversation 时如何传递@conversation.initiator = User.first@conversation.recipient = User.third

class Conversation < ApplicationRecord
  belongs_to :initiator, foreign_key: :initiator_id, class_name: 'User'
  belongs_to :recipient, foreign_key: :recipient_id, class_name: 'User'
end

class User < ApplicationRecord
  has_many :conversations
end

【问题讨论】:

  • 您可以将其作为 hidden_​​field_tag 传递,例如
  • @Navin,你能举例说明如何做到这一点吗? SO上还有其他问题没有给出明确的答案,也没有得到解决。
  • 使用其属性为您的@conversation 创建一个简单的 form_for,然后只需在 form_for 下添加 标记,您将在参数哈希中获得启动器。跨度>
  • @Navin,好吧,这行得通,现在我该如何通过强大的参数:params.require(:initiator) =&gt; &lt;ActionController::Parameters {"#&lt;User:0x007fe586ac7920&gt;"=&gt;""} permitted: false&gt;
  • 别那样做,你是否创建了强大的参数:params.require 用于对话,然后在同一个哈希中只允许发起者和接收者。

标签: ruby-on-rails actionview


【解决方案1】:

正如您所提到的,任何对话对象都将具有发起者和接收者属性,那么它将如下所示:

def new_form
    @conversation = Conversation.new(initiator: User.first, recipient: User.third)
end

现在您的模型对象@conversation 可以使用这两个值,您可以在表单中的任何位置访问它,如下所示:

new.html.erb

<%= form_for @conversation do |f| %>
    <%= f.text_field :body, :value => @conversation.initiator %>
<% end %>

希望对你有所帮助。

【讨论】:

    【解决方案2】:

    警告:

    如果您正在制作一个真正的消息应用程序,请不要按原样使用代码。

    绝不允许用户操作敏感数据。在下面的示例中,名为 Alice 的人可以编辑隐藏字段并注入 Bob 的 id,从而从 Bob 的帐户发送消息。

    我实际上是从 devise 的 current_user 助手中获取 Alice 的,并使用 pundit 来确保授权。

    解决方案:

    修复它,原来hidden_field标签的第一个参数必须是@variable,写成符号(:variable),第二个必须是:attribute

    然后你可以在param[:variable] #&gt; {attribute: value}下找到它

    恕我直言,这是完成此操作的一种愚蠢且不直观的方式,但是,嘿,它有效。然后你可以对其进行强参数化并将其加载到模型中。

    代码如下:

    在我的控制器的new 方法中:

    # GET /conversations/new
    def new
      @conversation = Conversation.new
      @initiator = User.first
      @recipient = User.second
    end
    

    然后在new.html.erb:

    <%= form_for @conversation do |f| %>
      <%= f.text_field :subject, class: "form-control" %>
    
      <%= hidden_field :initiator, :id %>
      <%= hidden_field :recipient, :id %>
    
      <%= f.button 'Submit', class: 'btn-primary pull-right' %>
    <% end %>
    

    然后在控制器的create方法中:

      def create
        @conversation = Conversation.new(conversation_params)
    
        @conversation.initiator = User.find_by(initiator_form_params)
        @conversation.recipient = User.find_by(recipient_from_params)
    
        if @conversation.save
          redirect_to :back, notice: 'Conversation was successfully created.'
        else
          redirect_to :back, notice: 'Conversation was not sent!'
        end
      end
    

    并创建强大的参数

      private
    
        def conversation_from_params
          params.require(:conversation).permit(:subject)
        end
    
        def initiator_from_params
          params.require(:initiator).permit(:id)
        end
    
        def recipient_from_params
          params.require(:recipient).permit(:id)
        end
    

    不客气,未来的我。

    【讨论】:

    • 请记住,恶意用户将能够更改隐藏的输入值并将其他内容发送回您的应用程序。如果您需要确保此安全,则应避免将initiator_idrecipient_id 传递给您的表单并返回。只需将它们与您的conversation_params 合并即可。例如,在您的 create 操作中:@conversation = Conversation.new(conversation_params.merge({initiator_id: User.first.id, recipient_id: User.second.id}))
    • @Teoulas 你是对的,这实际上正是我所做的,但它与原来的问题有点不同,所以我跳过了这部分。我还使用pundit 来授权正确的用户是否正在创建此对话。我应该用这个警告更新答案:)
    • 嗯,这取决于您是否信任您的用户。 pundit 不会确保他们不会弄乱您的隐藏输入。
    • @Teoulas:我为像我这样的人设计应用程序。我发送奇怪的输入只是为了弄乱应用程序。在我的真实应用程序中,我根本没有通过隐藏字段传递initiator,而是从用户会话中获取它。 Pundit 只是检查用户是否允许进行更改。
    猜你喜欢
    • 1970-01-01
    • 2011-05-18
    • 1970-01-01
    • 2018-07-01
    • 1970-01-01
    • 1970-01-01
    • 2022-06-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多