简体   繁体   English

Rails API:一个请求,多个控制器操作

[英]Rails API: One Request, Multiple Controller Actions

I have multiple models that in practice are created and deleted together. 我有多个在实践中一起创建和删除的模型。 Basically I have an Article model and an Authorship model. 基本上,我有一个Article模型和一个Authorship模型。 Authorships link the many to many relation between Users and Articles. 作者身份将用户与文章之间的多对多关系联系起来。 When an Article is created, the corresponding Authorships are also created. 创建文章时,还将创建相应的作者资格。 Right now, this is being achieved by POSTing multiple times. 目前,这是通过多次POST实现的。

However, say only part of my request works. 但是,仅说我的请求的一部分有效。 For instance, I'm on bad wifi and only the create article request makes it through. 例如,我的wifi不好,只有create article请求可以通过。 Then my data is in a malformed half created, half not state. 然后,我的数据处于错误创建的状态,一半处于未创建状态。

To solve this, I want to send all the data at once, then have Rails split up the data into the corresponding controllers. 为了解决这个问题,我想一次发送所有数据,然后让Rails将数据拆分为相应的控制器。 I've thought of a couple ways to do this. 我想到了几种方法来做到这一点。 The first way is having controllers handle each request in turn, sort of chaining them together. 第一种方法是让控制器依次处理每个请求,将它们链接在一起。 This would require the controllers to call the next one in the chain. 这将要求控制器调用链中的下一个。 However, this seems sorta rigid because if I decide to compose the controllers in a different way, I'll have to actually modify the controller code itself. 但是,这似乎有点僵化,因为如果我决定以其他方式构成控制器,则必须实际修改控制器代码本身。

The second way splits up the data first, then calls the controller actions with each bit of data. 第二种方法是先拆分数据,然后用数据的每一位调用控制器动作。 This way seems more clean to me, but it requires some logic either in the routing or in a layer independent of the controllers. 这种方式对我来说似乎更干净,但是在路由或独立于控制器的层中都需要一些逻辑。 I'm not really clear where this logic should go (another controller? Router? Middleware?) 我不清楚这个逻辑应该去哪里(另一个控制器?路由器?中间件?)

Has anybody had experience with either method? 有没有人有使用任何一种方法的经验? Is there an even better way? 有没有更好的办法?

Thanks, Nicholas 谢谢尼古拉斯

Typically you want to do stuff like this -- creating associated records on object creation -- all in the same transaction. 通常,您想要做这样的事情-在对象创建时创建关联记录-全部都在同一事务中进行。 I would definitely not consider breaking up the creation of an Authorship and Article if creating an Authorship is automatic on Article creation. 我绝对不会考虑分手的创建AuthorshipArticle ,如果创建一个Authorship是自动上Article创作。 You want a single request that takes in all needed parameters to create an Article and its associated Authorship , then you create both in the same transaction. 你想要的是发生在所有需要的参数,以创建单个请求Article 及其相关Authorship ,那么你在同一个事务中创建两个。 One way would be to do something like this in the controller: 一种方法是在控制器中执行以下操作:

class Authorship
  belongs_to :user
  belongs_to :article
end

class Article
  has_many :authorships
  has_many :users, through: :authorships
end

class ArticlesController
  def create
    @article = Article.new({title: params[:title], stuff: [:stuff]...})
    @article.authorships.build(article: @article, user_id: params[:user_id])
    if @article.save
      then do stuff...
    end
  end
end

This way when you hit @article.save , the processing of both the Article and the Authorship are part of the same transaction. 这样,当您单击@article.save ,对ArticleAuthorship都是同一事务的一部分。 So if something fails anywhere, then the whole thing fails, and you don't end up with stray/disparate/inconsistent data. 因此,如果某处发生任何故障,那么整个故障就会发生,并且您最终不会出现流浪/分散/不一致的数据。

If you want to assign multiple authorships on the endpoint (ie you take in multiple user id params) then the last bit could become something like: 如果要在终结点计算机上分配多个作者身份(即,使用多个用户ID参数),则最后一位可能类似于:

class ArticlesController
  def create
    @article = Article.new({title: params[:title], stuff: [:stuff]...})
    params[:user_ids].each do |id|
      @article.authorships.build(article: @article, user_id: id)
    end

    if @article.save
      then do stuff...
    end
  end
end

You can also offload this kind of associated object creation into the model via a virtual attribute and a before_save or before_create callback, which would also be transactional. 您还可以通过虚拟属性和before_savebefore_create回调将这种关联的对象创建卸载到模型中,这也将是事务性的。 But the above idiom seems more typical. 但是以上习语似乎更典型。

I would handle this in the model with one request. 我将在模型中处理一个请求。 If you have a has_many relationship between Article and Author , you may be able to use accept_nested_attributes_for on your Article model. 如果ArticleAuthor之间具有has_many关系,则可以在Article模型上使用accept_nested_attributes_for Then you can pass Authorship attributes along with your Article attributes in one request. 然后,您可以在一个请求中传递Authorship属性以及Article属性。

I have not seen your code, but you can do something like this: 我没有看到您的代码,但是您可以执行以下操作:

model/article.rb 型号/article.rb

class Article < ActiveRecord::Base
   has_many :authors, through: :authorship # you may also need a class_name: param
   accepts_nested_attributes_for: :authors
end

You can then pass Author attributes to the Article model and Rails will create/update the Authors as required. 然后,您可以将Author属性传递给Article模型,Rails将根据需要创建/更新Authors

Here is a good blog post on accepts_nested_attributes_for. 这是有关accepts_nested_attributes_for的不错的博客文章 You can read about it in the official Rails documentation . 您可以在Rails官方文档中阅读有关它的信息

I would recommend taking advantage of nested attributes and the association methods Rails gives you to handle of this with one web request inside one controller action. 我建议您利用嵌套属性和关联方法,Rails通过一个控制器操作中的一个Web请求来处理此问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM