Assignment: title:string
Permission: user_id:integer, subject_class:string, subject_id:integer, action:string
Assignment has_many :permissions, :foreign_key => :subject_id
But how do I make sure that it knows about the subject_class == self.class.to_s requirement?
Update: Using :conditions => {:subject_class => 'Assignment'}, how can I ensure when I do permissions.new the :subject_class is also set.
This is something you want to use polymorphic associations for (http://wiki.rubyonrails.org/howtos/db-relationships/polymorphic)
In your Assignment model, you would do the following:
has_many :permissions, :as => :subject
And in your Permission model, you would do this:
belongs_to :subject, :polymorphic => true
However, you'll need to rename the subject_class field to subject_type in order for this to work implicitly. When all of this is done, you'll have everything you asked for for free from Rails. You won't need to pass :subject_type when you create a new Permission. You can create a Permission like this and :subject_type will be filled automatically for you:
assignment = Assignment.create(:title => "My Assignment")
permission = Permission.create(:subject => assignment, :action => "read", :user => current_user)
- or -
assignment.permission.create(:user => current_user, :action => "read")
Related
This is a rather simple Rails 4 situation. Model Intranet has_many activities. Activities exists with sufficient records for several intranets. Current_intranet.activities.size returns 69 records. However, whenever I try to access any of the records, I receive "output error: <ArgumentError: wrong number of arguments (1 for 0)" even though I'm not passing any arguments. All of the following fail with that error.
Current_intranet.activities.first
Activity.where(intranet_id: 1).first
Activity.where(:intranet_id => 1).first
Activity.where{intranet_id.eq 1}.first
All of the above with [0] instead of first
There is no problem with any other models
I'd appreciate any suggestions. Thanks in advance.
There are no defined scopes. The code is:
class Activity < ActiveRecord::Base
acts_as_capitalized
# activities created during intranet creation.
DEFAULT_ACTIVITIES = { 'Document Preparation' => 'general income', 'No Charge' => 'general income'}
# static activity names that can not be deleted.
STATIC_ACTIVITY_NAMES = [ 'Document Preparation','No Charge']
before_destroy :check_if_used
before_destroy :cannot_delete_static_activities
belongs_to :created_by_user, :class_name => "User", :foreign_key => "created_by"
belongs_to :updated_by_user, :class_name => "User", :foreign_key => "updated_by"
belongs_to :intranet
belongs_to :chart_of_account
has_many :activity_rates, :dependent => :destroy
has_many :event_type
has_many :billings do
def find_by_name(name)
(find :all, :conditions => ["activity.name = ?",name])
end
end
has_many :document_templates, :foreign_key => "billing_activity_id"
validates_presence_of :intranet_id, :name, :chart_of_account_id
validates_uniqueness_of :name, :scope => :intranet_id
class User < ActiveRecord::Base
has_many :followings, :as => :followable, :dependent => :destroy, :class_name => 'Follow'
has_many :follows, :as => :follower, :dependent => :destroy
define_index do
has follows.followable(:id), :as => :followable_id
has followings.follower(:id), :as => :follower_id
has follows.followable(:type), :as => :followable_type
has followings.follower(:type), :as => :follower_type
end
end
question: I can not search by type (always empty array). A bug? I would like to get all users where followers are of type 'AAA'.
User.search '', :with => { :follower_type => 'AAA' }
question: Why do I have to inverse my association to get the right result (index definition):
follows.followable(:id), :as => :followable_id
instead of
followings.followable(:id), :as => :followable_id
I would like to get a list of followers for a user with id=1
User.search :with => {:followable_id => 1} # List of followers for a user with id=1
Thx!
With regards to the first question - string filters don't work in Sphinx. This should change in the future (with Sphinx 1.10-beta, once Thinking Sphinx supports the new features), but not sure when that'll happen (I'd love to say soon, but can't promise anything).
There is a workaround available, though... but keep in mind you're handling an array of strings, so that's an additional level of complexity.
As for the second question, struggling to get my head around what the database is looking like (confusing names, but I'm lacking focus right now), so I'll just leave it at this for the moment.
I have problem with my associations. I have n:n relation and everything going good but if i want initialize new object and then save it, it will by save with out associations. For example.
Models:
class User
has_many :users_in_organizations, :class_name => 'UserInOrganization'
has_many :organizations,:through => :users_in_organizations
end
#Attributes [:user_id, :organization_id, :user_role]
class UserInOrganization
set_table_name 'users_in_organizations'
belongs_to :user
belongs_to :organization
end
class Organization
has_many :users_in_organizations, :class_name => 'UserInOrganization'
has_many :users, :through => :users_in_organizations
end
this work fine but the problem is
org = User.first.organizations.new(:name => 'Test') # new || build is the same
org.save # => true
User.first.organizations # => []
Organization.all # => ['Test']
but if I use create then it works
org = User.first.organizations.create(:name => 'Test')
User.first.organizations # => ['Test']
Organization.all # => ['Test']
Can anybody tell me what i am doing wrong?
Thank You :)
If you want it working for new method, try this:
u = User.first
u.organizations.new :name => "new organozation"
u.save
u.organizations.size
=> 1
When you do org = User.first.organizations.new :name => "test" then you assign to org only organization and you save only that object. It doesn't save associated objects. That's why it doesn't work that way.
When you call create it saves created objects to db, using new or build doesn't save it to db.
Similar to this question, how do I set a property on the join model just before save in this context?
class Post < ActiveRecord::Base
has_many :post_assets
has_many :assets, :through => :post_assets
has_many :featured_images, :through => :post_assets, :class_name => "Asset", :source => :asset, :conditions => ['post_assets.context = ?', "featured"]
end
class PostAssets < ActiveRecord::Base
belongs_to :post
belongs_to :asset
# context is so we know the scope or role
# the join plays
validates_presences_of :context
end
class Asset < ActiveRecord::Base
has_many :post_assets
has_many :posts, :through => :post_assets
end
I just want to be able to do this:
#post = Post.create!(:title => "A Post")
#post.featured_images << Asset.create!(:title => "An Asset")
# ...
#post = Post.first
#featured = #post.featured_images.first
#=> #<Asset id: 1, title: "An Asset">
#featured.current_post_asset #=> #<PostAsset id: 1, context: "featured">
How would that work? I've been banging my head over it all day :).
What currently happens is when I do this:
#post.featured_images << Asset.create!(:title => "An Asset")
Then the join model PostAsset that gets created never gets a chance to set context. How do I set that context property? It looks like this:
PostAsset.first #=> #<PostAsset id: 1, context: nil>
Update:
I have created a test gem to try to isolate the problem. Is there an easier way to do this?!
This ActsAsJoinable::Core class makes it so you can have many to many relationships with a context between them in the join model. And it adds helper methods. The basic tests show basically what I'm trying to do. Any better ideas on how to do this properly?
Look at the has_many options in the ActiveRecord::Associations::ClassMethods API located here: http://rails.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#M001316
This is the most interesting quote:
:conditions
Specify the conditions that the associated object must meet in order to be included as a WHERE SQL fragment, such as authorized = 1. Record creations from the association are scoped if a hash is used. has_many :posts, :conditions => {:published => true} will create published posts with #blog.posts.create or #blog.posts.build.
So I believe your conditions must be specified as a hash, like so:
class Post < ActiveRecord::Base
has_many :post_assets
has_many :featured_post_assets, :conditions => { :context => 'featured' }
has_many :assets, :through => :post_assets
has_many :featured_images, :through => :featured_post_assets,
:class_name => "Asset", :source => :asset,
end
And you should also do the following:
#post.featured_images.build(:title => "An asset")
instead of:
#post.featured_images << Asset.create!(:title => "An Asset")
This should call the scoped asset build, as suggested in the quote above to add the context field to asset. It will also save both the join model object (post_asset) and the asset object to the database at the same time in one atomic transaction.
In a toy Rails application, I'm modelling a situation where you have a number of pots, each containing an amount of something, and you can make transactions between the pots. A transaction can come from any pot, and go to any pot.
Here are the relevant parts of the models:
class Pot < ActiveRecord::Base
has_many :to_transactions, :foreign_key => "to_id", :class_name => "Transaction"
has_many :from_transactions, :foreign_key => "from_id", :class_name => "Transaction"
end
class Transaction < ActiveRecord::Base
belongs_to :to_pot, :class_name => "Pot", :foreign_key => "to_id"
belongs_to :from_pot, :class_name => "Pot", :foreign_key => "from_id"
end
This allows me to do the following at the console:
>> p = Pot.find(123)
>> p.from_transactions
=> # returns array of transactions from pot 123
>> t = p.to_transactions.new
=> # t is a new transaction with to_id set to 123
and so on.
I'm having a problem setting up the routing. For example, I would like:
/pots/123/from_transactions to give a list of all transactions from pot 123,
/pots/123/to_transactions/new to give the new transaction form, with the to_id set to 123
Is this possible? Any help gratefully received etc etc.
I would say a clean way of managing is that all the from_transactions related request go to from_transactions_controller and to_transactions related go to to_transactions_controller. But the underlying model could be same for both:
In routing file you could specify your routes as follows:
'pots/:id/to_transactions/new', :controller => 'to_transactions', :action => 'new'
'pots/:id/from_transactions/', :controller => 'from_transactions', :action => 'index'
Does that help?
My routes.rb now includes the following:
map.resources :transactions, :path_prefix => '/pots/:from_id', :as => :from_transactions
map.resources :transactions, :path_prefix => '/pots/:to_id', :as => :to_transactions
This means, for example, that a request to /pots/123/from_transactions/new is sent to the transactions controller, and params[:from_id] is set to 123.