I need users to be able to become fans of other users. How should I design/set this up?
I need to be able to view details of user fans.
For example. I have user: Foo. Foo has 3 fans. I'd like to be able to find the names of Foo's fans. As such:
foo = User.first
foo.name (returns 'Foo')
foo.fans.first.user.name (should return 'bar', since 'bar' is a fan of 'foo')
This is how I have it set up at the moment:
User model:
embeds_many :fans
references_many :fans
Fan model:
embedded_in :user, :inverse_of => :fans
referenced_in :user
In console, I do:
User.first.fans.create!(:user => User.first)
and I get:
Mongoid::Errors::InvalidCollection: Access to the collection for Fan is not allowed since it is an embedded document, please access a collection from the root document. I think the problem is, because the fan model is embedded in the user model which has a self-reference to the user model as well....
Your thoughts will be much appreciated.
How about a self-referential association:
class User
include Mongoid::Document
references_many :fans,
:class_name => 'User',
:stored_as => :array,
:inverse_of => :fan_of
references_many :fan_of,
:class_name => 'User',
:stored_as => :array,
:inverse_of => :fans
end
# let's say we have users: al, ed, sports_star, movie_star
sports_star.fans << al
movie_star.fans << al
sports_star.fans << ed
movie_star.fans << ed
movie_star.fans # => al, ed
al.fan_of # => sports_star, movie_star
The problem is that you are trying to do relational association using only embedded documents. When you have a Fan embedded inside a User, you can only access the Fan through its parent User. You can't do something like Fan.find(some_id) because there is no collection of Fan records.
Eventually, MongoDB will support virtual collections that will allow you to do this. For now, you have to use relational-type associations. If you want to use embedded documents in this case, you have to create some ugly and inefficient custom methods to search through parent records.
With MongoDB and Mongoid, I have found that you can switch between embedded and relational associations easily. SQL-type relationships and embedded relationships both have their place and can be used together to great effect.
Related
I want to display just students in moodle users page without manually adding a filter using the web interface. Could anybody help me on how to do?
You can create a link that shows only students but you'll need to post the data. Here's how I did it.
If you install WebDeveloper - http://chrispederick.com/work/web-developer/
Then go to /admin/user.php and click WebDeveloper, choose the "Forms" tab and "convert POSTS to GETS".
Choose the filter and click add filter. This will display a url with all the form fields. Moodle is expecting a POST rather than a GET though.
So copy and paste the url into a variable and use the single_button function with the post method eg:
$url = '/admin/user.php?sesskey=xxxxxxx&_qf__user_add_filter_form=1&mform_showmore_id_newfilter=1&mform_isexpanded_id_newfilter=1&realname_op=0&realname=&lastname_op=0&lastname=&firstname_op=0&firstname=&email_op=0&email=&city_op=0&city=&country_op=0&confirmed=&suspended=&profile_fld=0&profile_op=0&profile=&courserole_rl=5&courserole_ct=0&courserole=&systemrole=0&cohort_op=2&cohort=&username_op=0&username=&auth=&deleted=&addfilter=Add+filter';
echo $OUTPUT->single_button($url, get_string('student'), 'post');
Copy and paste your own url rather than the above.
You can probably remove a lot of the parameters. You should also get the roleid for the student and use the moodle_url function, eg:
$studentroleid = $DB->get_field('role', 'id', array('shortname' => 'student'));
$params = array('courserole_rl' => $studentroleid, 'courserole_ct' => 0, ... );
$url = new moodle_url('/admin/user.php', $params);
echo $OUTPUT->single_button($url, get_string('students'), 'post');
This is not possible, as, in Moodle, it is rare for someone to be assigned the role of 'student' at the system level (and if you did, they would have access to every course on the site).
The concept of 'student' in Moodle only makes sense at the course level.
Let's say you're writing the software for Blogger.
Each user can create a blog post only if they are the owner of the blog. CanCan would normally define an ability check in this circumstance as:
user.can? :create, Post
However the user can only create the post if they are the owner of the current blog and there's no way to reference the current blog using only its classname. What I really need to be able to do is:
user.can? :create, Post, #current_blog
such that in the cancan definitions I can say
can :create, Post do |post, blog|
user == blog.owner
end
Is that possible or am I confused in how I'm approaching this?
Define an ability based on the parent of the current object:
can :create, Post, :blog => { :user => user }
This will make sure the current user can only create a new Post record for a blog that they are an owner of.
uses Post.blog_id to find parent Blog record
compares Blog.user_id field to current_user.id field
Also make sure that you are using a :through declaration when loading and authorizing your Post resource, so CanCan knows who the parent record is.
PostsController:
load_and_authorize_resource :through => :blog
See the CanCan wiki on GitHub for more detail.
You can use
user.can? :create_posts, #current_blog
or
user.can?:update, #current_blog
instead of
user.can? :create, Post, #current_blog
. Of course, you probably need to take out new and create action from load_and_authorize_resource. And test "authorization" by yourself
def new
unauthorized! if cannot? :create_posts, #current_blog
end
I'm not very confident about this schema design (suggestions welcome), but I have two collections:
Business
Customer
and each of them contains embedded documents:
Businesses contain Events
Customers contain Registrations
The class definitions are below, but first, the question. When I create a Business and add an Event, everything looks fine. When I create a Customer and add a Registration, everything looks fine. At this point, I can do:
ruby-1.9.2-p180 :380 > customer1.registrations.first.customer
=> #<Customer _id: BSON::ObjectId('4eb22a5bbae7a01331000019'), business_id: BSON::ObjectId('4eb215a9bae7a01331000001'), registrations: nil>
Perfect! But then... I add the Registration to the Event using event1.registrations << registration1, and now event1 has a different customer reference depending on whether I access it through the Event or through the Customer:
ruby-1.9.2-p180 :444 > customer1.registrations.first.customer
=> #<Customer _id: BSON::ObjectId('4eb22a5bbae7a01331000019'), business_id: BSON::ObjectId('4eb215a9bae7a01331000001'), posts: nil>
ruby-1.9.2-p180 :445 > business1.events.first.registrations.first.customer
=> #<Event _id: BSON::ObjectId('4eb21ab2bae7a0133100000f'), business_id: BSON::ObjectId('4eb215a9bae7a01331000001'), posts: nil>
ruby-1.9.2-p180 :446 > business1.events.first.registrations.first == customer1.registrations.first
=> true
Not perfect.... my best guess is that duplicates of registration1 have been embedded in both customer1 and event1? What I wanted was links between the Event and its many Registrations (which are owned and embedded in Customers). Is that possible with this schema?
This is what my models look like. They all have additional (and irrelevant) keys that are not displayed:
class Business
include MongoMapper::Document
many :events
many :customers
end
class Event
include MongoMapper::EmbeddedDocument
embedded_in :business
many :registrations
end
class Customer
include MongoMapper::Document
belongs_to :business
key :business_id, ObjectId
many :registrations
end
class Registration
include MongoMapper::EmbeddedDocument
embedded_in :customer
belongs_to :event
key :event_id, ObjectId
end
Yep. Registration is a MongoMapper::EmbeddedDocument so it's always embedded. That means because both Customer and Event have many :registrations, different registration objects will be embedded in each.
In MongoMapper, the embedded_in :customer just alias a customer method to return the document's parent. It's just a fancier way of calling _parent_document. That's why your event's registration's customer is an event object. (See source here).
The rule of thumb is to only embed when the child will always be used in context of its parent.
I am new to mongo/mongoid and I am trying to setup a self referencing relationships on my sites table.
# sites model
has_many :child_sites, :class_name => 'Site'
belongs_to :parent, :class_name => 'Site'
#controller
#event = current_site.child_sites.build(params[:site])
current_site is a function that returns the current site object.
I get this error -
undefined method `entries' for #
You can try changing your relation definitions to the following:
has_many :child_sites, :class_name => 'Site', :cyclic => true
belongs_to :parent_site, :class_name => 'Site', :cyclic => true
I don't know exactly what it does, but I remember it being discussed in the Mongoid google group. If that doesn't work, you should try to set inverse_of on both the relation macros. Most of the time setting inverse_of correctly does the job.
has_many :child_sites, :class_name => 'Site', :inverse_of => :parent_site
belongs_to :parent_site, :class_name => 'Site', :inverse_of => :child_sites
About the extra queries, yes there would be extra queries whenever you want to fetch child_sites of a site or the parent site of a site.
You should consider embedding child sites in parent site, but keep in mind that way you would loose the ability to query child sites in a stand_alone manner. You would always have to access any child site as "parent_site > child_sites".
Also keep in mind the 16MB limit on size of document, which is hard to reach, but might be possible if there are a lot of child sites for a parent and if you are storing template info, like html, css etc. in the document itself.
Cyclic was originally implemented for embedded documents (see user group entry). To make this working on mongoid 2.3 or higher you have to remove the cyclic option:
has_many :child_sites, :class_name => 'Site'
belongs_to :parent_site, :class_name => 'Site'
Can't you use recursively_embeds_many or recursively_embeds_one? http://mongoid.org/en/mongoid/docs/relations.html#common
I am using drupal 6. I have a node called [classroom]. I would like to have a [vacancy register] associated with each classroom.
vacancy register is a cck type with:
- uid
- nid
- join date
I would like for each user to [register] for a vacancy. I think I can use flag for this.
When a user joins, I can use rules to action an email to be sent to the user and the [classroom]->cck_email field.
I would like a rule schedule to also run every 30 days ( configurable ) to alert the user to confirm their [registration].
1a. If no registration is confirmed, then 14 days later, the user is [unregistered] from the classroom.
1b. If user confirms registration ( by clicking on a button or url ). then the rule 1 runs again.
I would like to confirms if my approach to this is correct.
Update:
I have been playing around with signup, but there are the rules schedule aspect of it that I find hard customising to my liking.
I'm trying to write a rules event for signup_signup and signup_cancel, then action it through rules schedule. But there a bit of existing signup code I have to look through.
Have to do too much custom work to signup, so I thought, its easier to just do it with rules and flags. The downside is having to also create the UI for it.
For the signup module,
I have the following rules event.
Could this be reviewed please?
<http://drupal.org/node/298549>
function signup_rules_event_info() {
return array(
'signup_signup' => array(
'label' => t('User signups to classroom'),
'module' => 'Signup',
'arguments' => array(
'userA' => array('type' => 'user', 'label' => t('UserA, which adds userB.')),
'userB' => array('type' => 'user', 'label' => t('UserB, which is added to UserA\'s list.')),
),
),
);
}
I don't know what to do with the arguments list.
I haven't looked at the signup module for some time, but I think that might be a better module for your case. The flag module is a good choice too, but the signup module is more geared towards what you are doing. Users signing up for content like a classroom.