如何将Rails中的附加参数从控制器传递到模型

时间:2014-08-31 10:59:09

标签: ruby-on-rails ruby ruby-on-rails-4

我想传递一个额外的字段,比如说item_id到这些代码行(控制器和模型):

# transactions_controller.rb (controller)
@transaction = Transaction.new(app_token: params[:token])

# transaction.rb (model)
def app_token=(token)
    write_attribute(:app_token, token)

    # I want to add a few more lines of code here so that I can manipulate item_id
end

这意味着,我希望我的item_id从控制器传递到模型,以便我可以操作它在模型中进行一些自定义。

这样做的最佳方法是什么(基于上面的代码)?

===更新于2014年9月1日,了解更多详情===

我有购物车和交易的关联,其中购物车has_many交易和交易belongs_to cart;下面是控制器;

# transactions_controller.rb (controller)
def new
  @transaction = Transaction.new(app_token: params[:token])
end

虽然以下方法在模型中:

# transaction.rb (model)
def app_token=(token)
    write_attribute(:app_token, token)

    # I want to add a few more lines of code here so that I can manipulate cart.id
end

我想在这里实现的是将cart.id传递到位于transaction.rb中的app_token方法。请注意,这个cart.id并不是要保存到数据库中,我可以通过构建方法通过create方法轻松完成,而是将此cart.id传递给方法以调用其他方法。在app_token方法中,该方法位于transaction.rb模型中。我这样做的原因是因为,我正在与之通信的服务返回一个令牌,我想持有令牌并执行另一个需要cart.id进入的方法。

因此,我只想了解一下,基于上面控制器和模型的给定格式,最推荐的方法是将此cart.id传递到位于transaction.rb模型中的app_token方法中。我想用于方法中的其他功能吗?

谢谢!

3 个答案:

答案 0 :(得分:1)

您不需要覆盖 app_token =

# transactions_controller.rb (controller)
@transaction = Transaction.new(app_token: params[:token], item_id: params[:item_id])
@transaction.save

答案 1 :(得分:1)

<强>属性

这主要取决于您是否将item_id设置为虚拟或数据库中的属性。

如果您已经设置了关联foreign_key,那么您就可以打折我要写的内容,但是如果您还没有,那么您应该考虑以下内容:

#app/models/transaction.rb
class Transaction < ActiveRecord::Base
   belongs_to :item # -> expects item_id by default
end

如果您没有设置关联(因此没有属性),您将要使用attr_accessor创建虚拟属性:

#app/models/transaction.rb
class Transaction < ActiveRecord::Base
   attr_accessor :item_id
end

<强> PARAMS

在Rails 4中传递属性实际上是您最不关心的问题 - 您可以根据需要在路径中传递尽可能多的属性。当您尝试将项目与db对象匹配时(因此我的建议)

,会出现问题

如果您想传递item_id属性,则只需确保在视图中设置该属性即可。这可以通过您的routes完成,也可以在表单中传递:

#config/routes.rb
resources :items
  resources :transactions #-> domain.com/items/:item_id/transactions/new
end

这将允许您传递您希望的item_id(它将作为params[:item_id]加载到您的控制器中。您还可以使用以下内容:

#app/views/transactions/new.html.erb
<%= form_for @transaction do |f| %>
   <%= f.text_field :item_id %>
   <%= f.text_field :token %>
   <%= f.submit %>
<% end %>

这将使您能够将两个不同的属性发送到您的控制器,然后可以填充如下:

#app/controllers/transactions_controller.rb
class TransactionsController < ApplicationController
   def new
      @transaction = Transaction.new
   end

   def create
      @transaction = Transaction.new transaction_params
      @transaction.save
   end

   private

   def transaction_params
      params.require(:transaction).permit(:item_id, :token)
   end
end

必须注意,form方法只有在模型中定义了属性时才可行 - 无论是在数据库中还是虚拟(使用attr_accessor

答案 2 :(得分:1)

  

我有购物车和交易的关联,其中购物车has_many交易和交易belongs_to cart

既然如此,你已经拥有了一个购物车对象,那么在你的控制器中只需从购物车中实例化交易:

transaction = cart.transactions.build app_token: params[:token]
transaction.save
然后

cart_id将可用于模型中的所有实例方法,因此无需使用与app_token无关的其他逻辑扩展app_token=。相反,利用ActiveRecord回调。例如,您可以使用before_save回调来实现您的逻辑:

class Transaction < ActiveRecord::Base
  belongs_to :cart
  before_save :do_something_with_cart

  def do_something_with_cart
    # I want to add a few more lines of code here so that I can manipulate cart_id
  end
end

如果由于某种原因回调不适合您使用casae,请直接在控制器中调用自定义方法:

transaction = cart.transactions.build app_token: params[:token]
transaction.do_something_with_cart