Rails 3: What associations should I use to create model relationships - ruby-on-rails

I am creating an app for uploading and sharing files between users.
I have User and Files models and have created a third File_Sharing_Relationships model which contains a sharer_id, file_id and shared_with_id columns. I want to be able to create the following methods:
#upload.file_sharing_relationships - lists users that the file is shared with
#user.files_shared_with - lists files that are shared with the user.
#user.files_shared - lists files that the user is sharing with others
#user.share_file_with - creates a sharing relationship
Are there any rails associations, such as 'polymorphic' that I could be using to make these relationships?
Any suggestions appreciated. Thanks.

All you need to do is to read Rails Guides and apply all what you learn.
Basically you need to store info about:
user who created a "sharing"
user or group or whatever is a target of a sharing action
resource that is being shared
So:
class SharedItem < ActiveRecord::Base
belongs_to :sharable, :polymorphic => true #this is user, please think of better name than "sharable"...
belongs_to :resource, :polymorphic => true #can be your file
belongs_to :user
end
You need SharedItem to have:
user_id: integer, sharable_id: integer, sharable_type: string, resource_id: integer, resource_type: string
Then you can get "methods" you specified by writing named scopes like:
named_scope :for_user, lambda {|user| {:conditions => {:user_id => user.id} }}
or by specifying proper associations:
class File < ActiveRecord::Base
has_many :shared_items, :as => :resource, :dependent => :destroy
end

I think you should create relationships something like this:
class User
has_many :files
has_many :user_sharings
has_many :sharings, :through => :user_sharings
end
class File
belongs_to :user
end
class Sharing
has_many :user_sharings
has_many :users, :through => :user_sharings
end
class UserSharing
belongs_to :user
belongs_to :sharing
end
.. this is very basic model of relations(It is just my point of view :)). User can have many sharings and also belongs to sharings. You can set file id to UserSharing table when you create user and it's share. And then you can create methods, you listed above, as scopes in proper models. I hope I helped you a little.

Related

rails - belongs_to any different model

I have some models in my database:
- customer
has_many documents
- charts
has_many documents
- pages
has_many documents
Any of models above can have many documents.
How can I do this in the Document model? Is there any relationship can accept different models?
Yes, it is possible. This concept is called polymorphic association and can be done like this using Ruby on Rails:
class Document < ActiveRecord::Base
belongs_to :owner, polymorphic: true
class Customer < ActiveRecord::Base
has_many :documents, as: :owner
It uses 2 columns to work: one column to save the owner's type, and a second column to save th owner's id:
Document.create(owner_type: 'Customer', owner_id: customer.id)
Then, you can call the method .owner on the document object:
doc = Document.first
doc.owner # => Can either return a Customer, Chart or Page record
You might want to add some security around this, something to prevent from creating documents for a owner that is not supposed to have this relation:
class Document < ActiveRecord::Base
belongs_to :owner, polymorphic: true
validates :owner_type, inclusion: { in: %w( Customer Chart Page ) }
This will prevent from creating documents like this:
Document.create(owner_type: 'kittyCat', owner_id: 77) # won't work

Create an object with several associations

If I have a user and article model with an association has_many :articles and belongs_to :user, I would write user.articles.new to create a new article object with the correct user_id .
So my question is about a model with many belongs_to relations:
class Ownership < ActiveRecord::Base
attr_accessible :right_read, :right_create, :right_update, :right_delete
belongs_to :element
belongs_to :user
belongs_to :ownership_type
end
Is there a solution to create an object Ownership with the 3 IDs completed (element_id, user_id, ownership_type_id) ?
And is it dangerous to write this IDs in the "attr_accessible" ?
Thank you.
The new method accepts a hash where the keys match the attributes in the model. This should work just fine:
Ownership.new(:element_id => element_id, :user_id => user_id, :ownership_type_id => ownership_type_id)
Reference: http://apidock.com/rails/ActiveRecord/Base/new/class
Also, no, it's not dangerous to include those attributes under attr_accessible -- actually, that's the only way you'll be able to directly write to them using new or update_attributes.

has_one :through => multiple

Both Attendment & Vouching:
belongs_to :event
belongs_to :account
Therefore: 1 to 1 relationship between attendments and vouchings.
Is there a way to do this without my thinking too much?
# attendment
has_one :vouching :through => [:event, :account]
Note: I don't mind thinking too much, actually.
Yeah i don't think you can use a has_one for this. Assuming I'm reading this correctly, you have two models:
Attendment
Vouching
They both store an event_id and account_id. You want to know from the attendment model, what vouching shares the same event and account as the attendment. I think the easiest solution for this is to write a method inside your attendment.rb file.
class Attendment < ActiveRecord::Base
# belong to statements go here
def voucher
Voucher.where(:event_id => self.event_id, :account_id => self.account_id).first
end
end

Making record available only to certain models in Rails 3

I have a weird design question. I have a model called Article, which has a bunch of attributes. I also have an article search which does something like this:
Article.project_active.pending.search(params)
where search builds a query based on certain params. I'd like to be able to limit results based on a user, that is, to have some articles have only a subset of users which can see them.
For instance, I have an article A that I assign to writers 1,2,3,4. I want them to be able to see A, but if User 5 searches, I don't want that user to see. Also, I'd like to be able to assign some articles to ALL users.
Not sure if that was clear, but I'm looking for the best way to do this. Should I just store a serialized array with a list of user_id's and have -1 in there if it's available to All?
Thanks!
I would create a join table between Users and Articles called view_permissions to indicate that a user has permission to view a specific article.
class ViewPermission
belongs_to :article
belongs_to :user
end
class User
has_many :view_permissions
end
class Article
has_many :view_permissions
end
For example, if you wanted User 1 to be able to view Article 3 you would do the following:
ViewPermission.create(:user_id => 1, :article_id => 3)
You could then scope your articles based on the view permissions and a user:
class Article
scope :viewable_by, lambda{ |user| joins(:view_permissions).where('view_permissions.user_id = ?', user.id) }
end
To search for articles viewable by a specific user, say with id 1, you could do this:
Article.viewable_by(User.find(1)).project_active.pending.search(params)
Finally, if you want to assign an article to all users, you should add an viewable_by_all boolean attribute to articles table that when set to true allows an article to be viewable by all users. Then modify your scope to take that into account:
class Article
scope :viewable_by, lambda{ |user|
joins('LEFT JOIN view_permissions on view_permissions.article_id = articles.id')
.where('articles.viewable_by_all = true OR view_permissions.user_id = ?', user.id)
.group('articles.id')
}
end
If an Article can be assigned to multiple Writers and a Writer can be assigned to multiple Articles, I would create an Assignment model:
class Assignment < AR::Base
belongs_to :writer
belongs_to :article
end
Then you can use has_many :through:
class Article < AR::Base
has_many :assignments
has_many :writers, :through => :assignments
end
class Writer < AR::Base
has_many :assignments
has_many :articles, :through => :assignments
end

Rails + simple role system through associative table

So I have the Ninja model which has many Hovercrafts through ninja_hovercrafts (which stores the ninja_id and the hovercraft_id).
It is of my understanding that this kind of arrangement should be set in a way that the associative table stores only enough information to bind two different classes.
But I'd like to use the associative table to work as a very streamlined authorization hub on my application. So i'd also like this table to inform my system if this binding makes the ninja the pilot or co-pilot of a given hovercraft, through a "role" field in the table.
My questions are:
Is this ugly?
Is this normal?
Are there methods built into rails that would help me to automagically create Ninjas and Hovercrafts associations WITH the role? For exemple, could I have a nested form to create both ninjas and hcs in a way that the role field in ninjas_hovercrafts would be also filled?
If managing my application roles this way isn't a good idea, whats the non-resource heavy alternative (my app is being designed trying to avoid scalability problems such as excessive joins, includes, etc)
thank you
This might not answer you question completely, but if you are only going to have two roles for hovercrafts I would instead set up the associations like this
class Hovercraft < ActiveRecord::Base
belongs_to :pilot, :class_name => 'Ninja', :foreign_key => 'pilot_id'
belongs_to :copilot, :class_name => 'Ninja', :foreign_key => 'copilot_id'
end
class Ninja < ActiveRecord::Base
has_many :pilotings, :class_name => 'Hovercraft', :foreign_key => 'pilot_id'
has_many :copilotings, :class_name => 'Hovercraft', :foreign_key => 'copilot_id'
end
Now if you have more roles than that, or if you need more flexibility you can use a third model to link them together.
class Hovercraft < ActiveRecord::Base
has_many :hovercraft_roles
has_many :ninjas, :through => :hovercraft_roles
end
class HovercraftRole < ActiveRecord::Base
belongs_to :hovercraft
belongs_to :ninja
end
class Ninja < ActiveRecord::Base
has_many :hovercraft_roles
has_many :hovercrafts, :through => :hovercraft_roles
end
With a role attribute in HovercraftRole model to indicated if it is a 'pilot' or 'copilot'.

Resources