public activity and Notifications in rails - android-activity

i am designing this little application which consists of Users, Activities,Comments and Notifications.
Users has many activities, Comments and notifications. the Activity was designed following ryan bates tutorial of PublicActivity from scratch 407-activity-feed-from-scratch. and also each Activity has many Comments. for the Notifications, it also belongs to the user in such a way that when a Comment is created, a notification is generated, so far my code includes
User Model
class User < ActiveRecord::Base
has_many :comments, :dependent => :destroy
has_many :notifications, :dependent => :destroy
has_many :activities, :dependent => :destroy
end
Activity Model
belongs_to :user
belongs_to :trackable, polymorphic: true
has_many :comments
has_many :notifications
default_scope :order => "activities.created_at DESC"
#scope :recent, where(published_at: Time.now - 2.weeks)
end
Comment Model
class Comment < ActiveRecord::Base
belongs_to :activity
belongs_to :user
default_scope :order => "comments.created_at DESC"
end
Notification Model
class Notification < ActiveRecord::Base
belongs_to :user
belongs_to :activity
end
in the controller,
Comments controller i have tried this
def new
#comment = Comment.new
end
def create
#activity = Activity.find(params[:activity_id])
#comment = #activity.comments.create!(comment_params)
#comment.user = #user
#comment.save
#users= User.joins(:comments).where(comments: {id: #activity.comment_ids}).push(#activity.user).uniq_by {|a| a[:user_id]}
#users.each do |user|
Notification.create(activity_id:#activity, user_id: user.id)
end
redirect_to user_path(current_user)
end
Activity Controller
def index
#activities = Activity.all(:include => :comments, :order => "created_at DESC")
#comments = Comment.find(:all, :order => "created_at DESC")
#comment = Comment.new
#comment.user = current_user
end
Notification Controller
def index
#notifications = current_user.notifications
end
WHAT I WANT TO ACHIEVE IS, NOTIFICATIONS SHOULD BE Created And Available To:
the owner of the activity cos each activity belongs to a particular user i.e when a new comment is created by another user, a notification is available to the owner of the activity.
SHOULD NOT! be available to the new commenter i.e the user that as just commented on the activity but available to owner of the activity
Available to all previous commenters i.e every user that as commented on that activity
and the owner of the activity
. for now my code above does not work and also is there anything am doing wrong with the model and controllers?

basically what i will do is get all Users that commented on the activity with the following
##Activity model
has_many :comments
has_many :users, -> {uniq}, through: :comments
So now your new comment create action will look like this
def create
#activity = Activity.find(params[:activity_id])
#comment = #activity.comments.create!(comment_params)
#comment.user = #user
#comment.save
#users= #activity.users.where("id NOT IN (?)", [#activity.user.id, #comment.user])
## Lets create a notification for all those who created a comment in this activity
#users.each do |user|
Notification.create(activity:#activity, user: user)
end
## Lets create a notification for the owner activity
Notification.create(activity:#activity, user: #activity.user)
redirect_to user_path(current_user)
end
This code is not optimized but can help you out

Related

Save lab price on model to database rails

I have 3 models has_many, through relation : lab, medic_record, and lab_medic. In medic_record model, i have a method to calculate lab price and i have created a migration too for add column "lab_price:decimal" to medic_record
medic_record.rb
has_many :lab_medics, :dependent => :destroy
has_many :labs, :through => :lab_medics
before_save :finalize
def lab_price
Lab.where(:id => self.lab_ids).reduce(0) { |sum, x| sum += x[:price].to_f }
end
private
def finalize
self[:lab_price] = lab_price
end
lab.rb
has_many :lab_medics, :dependent => :destroy
has_many :medic_records, :through => :lab_medics
lab_medic.rb
belongs_to :lab
belongs_to :medic_record
My question is how to save a lab_price in medic_record model to database 'column :lab_price'? I have tried using 'before_save :finalize' method but the result on database always "0.0" after i created new record for medic_record.
SOLVED
I has changed method with this and its worked !!
def self.save_tot(medic)
medic.update_attributes(lab_price: Lab.where(:id => medic.lab_ids).reduce(0) { |sum, x| sum += x[:price].to_f })
end

Connecting database view with polymorphic model in rails

I have the following setup which allows a user to have multiple projects and each project can have multiple tasks. A user can favourite multiple projects.
class User < ActiveRecord::Base
has_many :projects
has_many :tasks, :through => :projects
has_many :favourites
has_many :favourite_projects, :through => :favourites, :source => :favourable, :source_type => "Project"
has_many :favourite_tasks, :through => :favourite_projects, :source => :tasks
...
end
class Project < ActiveRecord::Base
belongs_to :user
has_many :tasks
has_many :favourites, :as => :favourable
...
end
class Task < ActiveRecord::Base
belongs_to :project
...
end
class Favourite < ActiveRecord::Base
belongs_to :user
belongs_to :favourable, :polymorphic => true
...
end
This setup allows #user.favourite_tasks to list all the tasks for the projects that they have favourited.
Taking the suggestion from here (http://pivotallabs.com/database-views-performance-rails/) I am trying to replace the multi-level table joins with a database view where possible instead.
The view SQL is:
SELECT tasks.id AS task_id, ..., projects.id AS project_id, ...
FROM tasks INNER JOIN projects ON projects.id = tasks.project_id
My new ProjectTask model is:
class ProjectTask < ActiveRecord::Base
self.primary_key = 'task_id'
end
I've updated my User model to include:
has_many :project_tasks
which works fine for #user.project_tasks.
However, I can't figure out what the has_many/has_one/belongs_to should be in the models for the favourites to work (connecting the favourites to the view rather than the projects table).
I'm aiming for has _many :favourite_project_tasks, :through => :favourites.... so that I can use #user.favourite_project_tasks in my controller and attach any ProjectTask model scopes to it if need be.
I think the fact that the ProjectTask model has task_id as the primary key is causing issue with rails linking the tables/view and because using :through overrides any use of :foreign_key and :primary_key (according to http://apidock.com/rails/ActiveRecord/Associations/ClassMethods/has_many).
Hopefully someone can advise what I should be doing because I've tried loads of combinations of changes with no joy.
Thanks
Issue seems to have been caused by the custom primary key.
By updating the User model with (I was already doing this when it was failing):
has_many :favourite_project_tasks, :through => :favourite_projects, :source => :project_tasks
to use the view and also changing the view to use:
SELECT tasks.id AS id, ...
rather than:
SELECT tasks.id AS task_id, ...
and changing the ProjectTask view model to use:
self.primary_key = :id
it now works.

Associates the same model twice through different name

I am trying to implement a lost and found database.
I have two model, User and Item. A user can lost an an item and found an item. And a item can have a the user who found it and the user who lost it. I want to be able to reference the the same model through different name, e.g.
user.found_items, user.lost_items, item.founder, item.losser
right now I am able to do:
user.founds, user.losts and user.items will return the items from losts
class User < ActiveRecord::Base
has_many :founds
has_many :items, through: :founds
has_many :losts
has_many :items, through: :losts
end
class Lost < ActiveRecord::Base
belongs_to :user
belongs_to :item
end
class Found < ActiveRecord::Base
belongs_to :user
belongs_to :item
end
class Item < ActiveRecord::Base
has_one :found
has_one :user, through: :found
has_one :lost
has_one :user, through: :lost
end
I would do something pretty similar just rename them for clarity and add some methods for the functions you wanted.
class User < ActiveRecord::Base
has_many :found_items
has_many :items, through: :found_item
has_many :lost_items
has_many :items, through: :lost_item
def items_found
self.found_items.map {|i| i.item.name }
end
def items_lost
self.lost_items.map {|i| i.item.name }
end
end
class LostItem < ActiveRecord::Base
belongs_to :user
belongs_to :item
end
class FoundItem < ActiveRecord::Base
belongs_to :user
belongs_to :item
end
class Item < ActiveRecord::Base
has_one :found_item
has_one :user, through: :found_item
has_one :lost_item
has_one :user, through: :lost_item
def finder
self.found_item.user.name
end
def loser
self.lost_item.user.name
end
end

User does not store in database after successful login from Devise thru Omniauth (Rails 3)

It seems that I cannot save users from my database even though omniauth controller confirms successful login. I followed the instructions from the omniauth wiki: https://github.com/plataformatec/devise/wiki/OmniAuth%3A-Overview
user.rb:
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable,
# :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable, :omniauthable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :encrypted_password, :provider, :uid
attr_accessor :email, :password, :password_confirmation, :remember_me, :provider, :uid, :name
def self.from_omniauth(auth)
where(auth.slice(:provider, :uid)).first_or_initialize.tap do |user|
user.provider = auth.provider
user.uid = auth.uid
user.email = auth.info.email
user.encrypted_password = Devise.friendly_token[0,20]
user.save!
end
end
def self.find_for_facebook_oauth(auth, signed_in_resource=nil)
user = User.where(:provider => auth.provider, :uid => auth.uid).first
unless user
user = User.create(
provider:auth.provider,
uid:auth.uid,
email:auth.info.email,
encrypted_password:Devise.friendly_token[0,20]
)
#user.ensure_authentication_token!
#added extra to create authentication for user
user.save
end
user
end
def self.new_with_session(params, session)
super.tap do |user|
if data = session["devise.facebook_data"] && session["devise.facebook_data"]["extra"]["raw_info"]
user.email = data["email"] if user.email.blank?
end
end
end
end
omniauth_callback_controller.rb:
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
def passthru
render :file => "#{Rails.root}/public/404.html", :status => 404, :layout => false
# Or alternatively,
# raise ActionController::RoutingError.new('Not Found')
end
def facebook
# You need to implement the method below in your model (e.g. app/models/user.rb)
#user = User.find_for_facebook_oauth(request.env["omniauth.auth"], current_user)
##user = User.from_omniauth(request.env["omniauth.auth"])
if #user.persisted?
sign_in_and_redirect #user, :event => :authentication #this will throw if #user is not activated
set_flash_message(:notice, :success, :kind => "Facebook") if is_navigational_format?
else
session["devise.facebook_data"] = request.env["omniauth.auth"]
#redirect_to new_user_registration_url
redirect_to messages_url
end
end
end
I've tried logging in with the default devise controller and it goes thru the users database.And since I cannot store to database, I cannot also get the uid.
Through creating a new application from a different approach: http://supriya-surve.blogspot.com/2012/06/rails-3-devise-omniauth-facebook.html, i found the solution.
Update user.rb find_for_facebook_auth:
def self.find_for_facebook_oauth(auth, signed_in_resource=nil)
user = User.where(:provider => auth.provider, :uid => auth.uid).first
unless user
user = User.create(
provider:auth.provider,
uid:auth.uid,
email:auth.info.email,
password:Devise.friendly_token[0,20]
)
end
user
end
Then the attr_accessible of user.rb:
attr_accessible :email, :password, :password_confirmation, :remember_me, :provider, :uid, :oauth_token, :oauth_expires_at
Upon successful login, user is saved to database.
I also had the same problem when I decided to add Tumblr authentication to an existing Devise user model. Turns out, Devise was throwing an error on the index_users_on_email database index.
Nobody on the net had that problem, so I thought I'd throw it out there. I spent a long time trying to figure it out. Glad you got it solved :)

Devise and OmniAuth: How to save facebook data for later use?

I have successfully implemented login with Facebook using Devise and OmniAuth (built into Devise). Now I need to figure out how to store the user's name in the database so that I can display their name for other users to see that they created/edited records in my application.
I must have copied this code from somewhere, and it looks like it should be working, but it is definitely not saving the name in the database:
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
def facebook
#user = User.find_for_facebook_oauth(env["omniauth.auth"], current_user)
if #user.persisted?
flash[:notice] = I18n.t "devise.omniauth_callbacks.success", :kind => "Facebook"
sign_in_and_redirect #user, :event => :authentication
else
session["devise.facebook_data"] = env["omniauth.auth"]
redirect_to new_user_registration_url
end
end
end
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable, :lockable and :timeoutable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :omniauthable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me
def self.find_for_facebook_oauth(access_token, signed_in_resource=nil)
data = access_token['extra']['user_hash']
if user = User.find_by_email(data['email'])
if user.first_name != data['first_name']
user.update_attributes :first_name => data['first_name']
end
user
else # Create an user with a stub password.
User.create!(:email => data['email'],
:first_name => data['first_name'],
:password => Devise.friendly_token[0,20])
end
end
def self.new_with_session(params, session)
super.tap do |user|
if data = session['devise.facebook_data'] && session['devise.facebook_data']['extra']['user_hash']
user.email = data['email']
end
end
end
end
What am I doing wrong?
Andrew, as written here: the method attr_accessible makes the attribute available for mass assignment.
You should put it like this:
attr_accessible :email, :password, :password_confirmation, :remember_me, :first_name