开发者

:has_many, :through with ActiveResource models

开发者 https://www.devze.com 2023-03-14 16:03 出处:网络
Three models on a UserService backend Rails app: class User < ActiveRecord::Base has_many :services has_many :members

Three models on a UserService backend Rails app:

class User < ActiveRecord::Base
  has_many :services
  has_many :members
  has_many :groups, :through => :members
  has_many :managed_groups, :class_name => "Group"
  accepts_nested_attributes_for :managed_groups, :services, :groups
end

class Group < ActiveRecord::Base
  has_many :members
  has_many :users, :through => :members
  belongs_to :manager, :class_name => "User", :foreign_key => :user_id 
  accepts_nested_attributes_for :users  
end

class Service < ActiveRecord::Base
  belongs_to :user
end

class Member < ActiveRecord::Base
  belongs_to :group
  belongs_to :user
end

Three ActiveResource models in a separate Rails front-end

class User < ActiveResource::Base
  self.site = "http://localhost:8801"
end

class Group < ActiveResource::Base
  self.site = "http://localhost:8801"
end

class Service < ActiveResource::Base
  self.site = "http://localhost:8801"
end

From the Front-end, it works to do

Service.first.user_id = User.first

Because Service.user_id is a belongs_to… it's a single property.

However I can't do either

User.first.groups << Group.first

or

Group.first.users << User.first

Nothing happens because the ActiveResource is just spawning GET requests.

In the int开发者_如何学Cerest of completeness, doing things like the following (on the front-end) also fails.

u = User.first
g = Group.first
u.groups.push(g)

and so on. I was assuming that going through the users_controller::update method would work, but now I question whether this is possible at all.

Anyone done a :has_many, :through with two ActiveResource models? Is there any way to affect the collection of an AR model? Do I need to manipulate the join table manually? (Thereby creating a members_controller?)


This might be something for more than StackOverflow- more for the core team.

It seems that either ActiveResource is being stupid about how it talks to a RESTful client, or ActiveRecord is being stupid about how it listens to one (Or, the alternative, and much more likely option, these two things just fundamentally can't talk to one another.)

To wit: Given User, Service, and Group above, my front-end, upon placing a PUT request on the back-end server at /users/1.xml the back-end logs the following parameters (some values removed for conciseness):

{"user"=>
  {"created_at"=>2011-06-23 02:58:15 UTC, 
   "id"=>1, 
   "name"=>"John Metta", 
   "updated_at"=>2011-06-23 02:58:15 UTC, 
   "managed_groups"=>[], 
   "services"=>[
     {"created_at"=>2011-06-23 02:58:15 UTC, 
      "id"=>1, 
      "updated_at"=>2011-06-23 02:58:15 UTC, 
      "user_id"=>1}
   ], 
   "groups"=>[
     {"created_at"=>2011-06-23 02:56:37 UTC, 
      "id"=>1, 
      "updated_at"=>2011-06-23 02:56:37 UTC,  
      "user_id"=>nil, 
      "users"=>[
        {"created_at"=>2011-06-23 03:36:28 UTC, 
         "id"=>6, 
         "name"=>"Jefferey", 
         "updated_at"=>2011-06-23 03:36:28 UTC}, 
        {"created_at"=>2011-06-23 02:59:36 UTC, 
         "id"=>2, 
         "name"=>"George", 
         "updated_at"=>2011-06-23 03:05:13 UTC}
       ]
     }, 
     {"created_at"=>2011-06-23 02:56:37 UTC, 
      "id"=>1, 
      "name"=>"Site Admin", 
      "updated_at"=>2011-06-23 02:56:37 UTC, 
      "user_id"=>nil, 
      "users"=>[
        {"created_at"=>2011-06-23 03:36:28 UTC, 
         "id"=>6, 
         "name"=>"Jefferey", 
         "updated_at"=>2011-06-23 03:36:28 UTC}, 
        {"created_at"=>2011-06-23 02:59:36 UTC, 
         "id"=>2, 
         "name"=>"George", 
         "updated_at"=>2011-06-23 03:05:13 UTC}, 
        {"created_at"=>2011-06-23 02:58:15 UTC, 
         "id"=>1, 
         "name"=>"John Metta", 
         "updated_at"=>2011-06-23 02:58:15 UTC}
       ]
     }
   ]
  },
  "id"=>"1"}

So, I can see a few issues with ActiveResource (or, more likely, how I am trying to use ActiveResource), but the main is this:

Since ActiveResource seems to know nothing about associations, it just bundles everything up in a dumb fashion. In otherwords, ActiveResource dumbly says "Duh, you have a list of groups, so I'll call it a 'groups'" instead of knowing that, in order for this to actually work, it should be saying "Hrm, you have a list of groups, and Group is another model, I'll call it groups_attributes so that it can be rebuilt into a list of groups on the other end.

Now, before I get flamed, I understand that 'groups_attributes' is an ActiveRecord vocabulary word, not a general REST word, so if ActiveResource started using it, it would break, say, my other back-end which runs on Scala.

However, given that Rails should be able to work with Rails, and given that ActiveResource has to be dumb about it, then it seems that ActiveRecord should be able to figure out that "This incoming RESTful model has objects contained that map to known models that are referenced, let's try to create those models and make it work.

Workable Solution:

I haven't thought about this enough to feel comfortable assuming that ActiveRecord should always automatically try to map an incoming parameter set's included MODEL-named parameters to a MODEL. That will require some more testing and thought. However, my solution has been to catch that incoming parameter set in the users_controller with something like the following:

  …
  begin
    groups = []
    params[:user][:groups].each do |g|
      groups << Group.find(g[:id])
    end
    params[:user][:groups] = groups
  rescue
    # Do something not incredibly stupid here
  end
  …

Which seems to grab things relatively cleanly. My fear is that this seems pretty bulky for Rails-- which usually has much more elegant solutions to things-- and that I'm missing something basic.

(In the interest of completion, I realize that there are other problems with that parameter string, such as: Since I bundle the group with the user, and the user with the group, I'm passing a ton of data around necessarily (like, the entire group, and all it's users) when I pass the user around. This needs some sort of proxy- like a list of Group IDs or something. More likely, my ActiveResource models should have methods wrapping those objects. I'm considering those problem outside the scope of this issue.)

0

精彩评论

暂无评论...
验证码 换一张
取 消