I have two users, let's call them UserA and UserB. UserA sends friend request to UserB. This results in creation of a new attribute called as 'Friendtokens' in the UserB's database. The database used is MongoDB.
Friendtokens: {"919839398393"=>{"atoken"=>"f704e803061e594150b09ad8acabfc6105ac85ab", "confirmed"=>true}}
Now, when UserA, decides to delete UserB, I need to modify Friendtokens of UserB's DB and delete the UserA's mobile no. from it.
Any guidance of how could I achieve this by writing a simple code in users_controller.rb would be highly appreciated.
You are providing little info. Here's a modelisation I can suggest :
class User
include Mongoid::Document
embeds_many :friend_tokens
field :phone_number
class FriendToken
include Mongoid::Document
embedded_in :user
belongs_to :friend, class_name: "User"
field :confirmed, type: Boolean
def phone_number
confirmed ? friend.phone_number : "Friend not confirmed, not showing user phone number !"
end
users_controller.rb
def create_friend_request
#user.friend_tokens << FriendToken.create(friend_request_params)
end
def confirm_friend_request
token = #userA.friend_tokens.select{|t| t.friend == #userB}.first
if token
token.confirmed = true
token.save
else
# Error message
end
end
def delete_friend
friend_for_A = #userA.friend_tokens.select{|t| t.friend == #userB}.first
# Check it has been found
if friend_for_A
# Delete friend token for A
friend_for_A.delete
# Switch to unconfirmed for user B (we can also assume the token exists)
friend_for_B = #userB.friend_tokens.select{|t| t.friend == #UserA}.first
friend_for_B.confirmed = false
friend_for_B.save
else
# Error messages
end
end
Related
I have two tables User (Devise) and Phones
I would like for it when the user signs up threw registrations done with devise, the user_id and the type of phone is loaded into the Phones table
But I am not sure how to do this. I have linked the User with Phones with
User.rb
has_many :phones
Phones.rb
belongs_to :user
db (schema)
t.index ["user_id"], name: "index_phones_on_user_id"
Any help would be appreciated
you can run an after_create callback on User model
after_create :assign_phone
private
def assign_phone
phone = phones.new
# assign required values
phone.save
end
As mentioned in the comments, phone.save will silently return false if there's an error, using !(bang) will raise and error another solution is checking if it is saved or not and then perform task that you want..
def assign_phone
phone = phones.new
# assign required values
if phone.save
#on successfull save
else
#on failure
end
end
in user.rb
after_create :assign_phone
def assign_phone
phone = self.phones.build
phone.save
end
This way you will not be able to add type of phone. However, if you want to save type as well then you have to override "create" method of devise/registrations_controller.rb
My Opportunity model looks like this:
class Opportunity < ApplicationRecord
# opportunity belongs to a user
belongs_to :user
def self.create_opportunity(params)
# Fetch opportunity params and user params from request parameters
opportunity_params = params[:opportunity_params]
user_params = params[:user_params]
opportunity = Opportunity.find_or_initialize_by(id: opportunity_params[:id])
opportunity.assign_attributes(opportunity_params)
opportunity.user = User.find_or_initialize_by(email: user_params[:email])
opportunity.user.assign_attributes(user_params)
opportunity.save
end
user.rb model
class User < ApplicationRecord
# validate user email
validates :email, presence: true, email: true
enum gender: { male:1, female:2 }
end
We create a new user if a user with the email provided does not exists. This works well when a new user is created, but doesn't work when there already is a user. The update for user model doesn't work.
For update on user to work, I need to specifically call opportunity.user.save
Any idea how to make this work without explicitly calling save on user model?
With this line you can create a new user if it does not exist and update its data.
opportunity.user.find_or_create_by(email: user_params[:email]).update(user_params)
This method will return true/false if the user has been updated or not. If you want the user created itself use this:
opportunity.user.find_or_create_by(email: user_params[:email]).tap{ |user| user.update(user_params) }
edit:
THIS HAS TO WORK:
opportunity.user = User.find_or_create_by(email: user_params[:email]).tap{ |user| user.update(user_params) }
I'm stuck on the best way to do this. Thanks in advance for any thoughts.
My app receives text messages from clients (Twilio) and then creates an email to send to the coach (user) the client works with. I'm having an issue of finding the email of the coach (user) based on the client that sent the text. The texts are successfully saving, I'm just missing the email of the coach (aka user.email).
Users > Clients > Text_Messages
I can currently assume that all clients are only owned by own coach.
Here is the text_messages_controller.rb (I've omitted non-relevant code):
class TextMessagesController < ApplicationController
before_filter :authenticate_user!, except: [:receive]
protect_from_forgery :except => ["receive"]
def receive
#text_message=TextMessage.create!(content: params[:Body], phone: params[:From], incoming_message: "true", sentstatus: "false")
# missing code to extract user.email somehow
if #text_message.save
render nothing: true, status: 200
else
puts 'ERROR: company or customer couldn\'t be loaded'
end
end
private
def text_message_params
params.require(:text_message).permit(:content, :scheduled_date, :client_id, :sentstatus, :phone)
end
end
Here is the text_message.rb model (just in case):
require 'twilio-ruby'
require 'date'
class TextMessage < ActiveRecord::Base
belongs_to :client, dependent: :destroy
end
I thought I would be able to use the text_message.phone to match to the client.phone, use the client.user_id to get the user (by id) and finally extract the email from the selected user. Unfortunately, that is not working.
So I'm making the assumption that Coach belongs_to Client. Sounds like first you have to find the Client. Maybe something like:
#client = Client.find_by(phone: params[:from])
Then find the coach email with:
#coach_email = #client.coach.email
Or if it is that a Client belongs to a User through a has_many association then it should still be:
#coach_email = #client.user.email
I'm working in a large Rails 2.3 application and I have data on a model that would like to move to another model. I need to do this is phases as there are places in the Rails code base that are reading and writing this model data and outside applications reading the table data directly via SQL. I need to allow a period of time where the attribute is synchronized on both models and their associated tables before I drop one model and table altogether.
My models have a has_one and belongs_to relationship like this:
class User < ActiveRecord::Base
has_one :user_email, :inverse_of => :user
accepts_nested_attributes_for :user_email
validates_presence_of :email
def email=( value )
write_attribute(:email, value)
user_email.write_attribute(:email, value)
end
end
class UserEmail < ActiveRecord::Base
belongs_to :user, :inverse_of => :user_email
validates_presence_of :email
def email=( value )
write_attribute(:email, value)
user.write_attribute(:email, value)
end
end
I'd like to do away with UserEmail and its associated table altogether, but for a time I need to keep email up-to-date on both models so if it's set on one model, it's changed on the other. Overriding email= on each model is straightforward, but coming up with a commit strategy is where I'm hitting a wall.
I have places in the code base that are doing things like:
user.user_email.save!
and I'm hoping to find a way to continue to allow this kind of code for the time being.
I can't figure out a way to ensure that saving an instance of User ensures the corresponding UserEmail data is committed and saving an instance of UserEmail ensures the corresponding User instance data is also committed without creating an infinite save loop in the call backs.
This is the flow I would like to be able to support for the time being:
params = { user: { email: 'foo#bar.com', user_email: { email: 'foo#bar.com' } } }
user = User.create( params )
user.email = "moo#bar.com"
user.save
puts user.user_email # puts "moo#bar.com"
user.user_email.email = "foo#bar.com"
user.user_email.save
user.reload
puts user.email # puts "foo#bar.com"
Is there a way to achieve this sort of synchronization between the User and UserEmail models so they are kept in sync?
If it helps, I can probably do away with accepts_nested_attributes_for :user_email on User.
Using ActiveModel::Dirty
In User model
after_save :sync_email, :if => :email_changed?
def sync_email
user_email.update_column(:email, email) if user_email.email != email
end
In UserEmail model
after_save :sync_email, :if => :email_changed?
def sync_email
user.update_column(:email, email) if user.email != email
end
Let's assume, for sanity's sake, that the models are "User" and "Cart", and the shared field is "email". I would do this:
#in User
after_save :update_cart_email
def update_cart_email
if self.changes["email"]
cart = self.cart
if cart.email != self.email
cart.update_attributes(:email => self.email)
end
end
end
#in Cart
after_save :update_user_email
def update_user_email
if self.changes["email"]
user = self.user
if user.email != self.email
user.update_attributes(:email => user.email)
end
end
end
Because we check if the other model's email has already been set, it shouldn't get stuck in a loop.
This works if you drop accepts_nested_attributes_for :user_email -- otherwise you'll get a save loop that never ends.
The user has a balance (user.balance).
The user can post bets on a game (bet.amount).
How could I stop the user from betting more than what is in their balance?
I assume I could create a validation that looks something like this?
def enough_funds?
#bet.bet_amount > self.current_user.balance
flash[:notice] = "You do not have the available funds for this bet"
end
I'm still new to rails, be gentle :)
You're on the right track:
class Bet < ActiveRecord::Base
belongs_to :user
validate :funds_suffiency
def funds_sufficiency
errors.add :bet_amount, "is more than your available balance" if bet_amount < user.balance
end
end
If Bet's :bet_amount is less than the related User's available :balance, the error will be added to :bet_amount attribute, invalidating the model instance.