Hoping someone can point me in the right direction with this.
I want to know if there's a way to view/fetch both new and old property values with DataMapper before the update method is called and compare the values.
The scenario is as follows:
I have a ticket resource and I need to notify various interested parties about changes made to the ticket. Email notification when the payment status changes, SMS notification when the ticket get's assigned to a support staff etc.
Currently, inside my Ticket class, I have set up a callback/filter like this:
before :update, :notify_changes
def notify_changes
ticket = Ticket.get(self.id) # Get the original
if ticket.status != self.status
# Send out the email notification
end
if ticket.assigned_support != self.assigned_support
# Send out the SMS notification
end
# ... etc
end
Is there a better or more efficient way to do this without hitting the database again at ticket = Ticket.get(self.id)?
Ok, I've figured this out myself. Here it is for reference if anyone else finds themselves asking the same question:
before :update, :notify_changes
def notify_changes
# The status property has been changed
if !dirty_attributes[Ticket.properties[:status]].nil?
# old status: original_attributes[Ticket.properties[:status]]
end
# The assigned_support property has been changed
if !dirty_attributes[Ticket.properties[:assigned_support]].nil?
# old status: original_attributes[Ticket.properties[:assigned_support]]
end
end
Inspiration Reference: This thread
Yes, I was referring to dirty when I asked that. Just to add a little more incase someone else comes across this question.
There are a few methods one can call to check the status of an attribute or model object.
- (Boolean) attribute_dirty?(name)
- (Boolean) clean?
- (Boolean) dirty?
- (Hash) dirty_attributes # your choice
- (Hash) original_attributes
These are part of DataMapper::Resource and can be found here:
http://rubydoc.info/github/datamapper/dm-core/master/DataMapper/Resource
Related
In the ruby controller, I have two methods in the same controller.
class NotificationsController < ApplicationController
def first
variable_one = xxxx
end
def second
// do something
end
end
I want to use the variable one in the method first, and use it in the method two. I tried to assign the variable one to a session hash. session[:variable_one] = variable_one, and access it in the method two. But it turns out the session[:variable_one] in the method two is nil. These two methods don't have the corresponding views, so I cannot add a link_to and pass parameters. The method one cannot be set as before_action as well.
Could you please have some suggestions on this problem? Thanks so much.
The issue that session is stored via cookie, and therefore it is specific to one device. So, you will have one session between the rails app and your frontend, and another session betweeen the rails app and Twilio (probably the Twilio session will reset between each request). Basically, they're totally separate contexts.
Possibly you could figure out how to pass the information along via Twilio - see https://www.twilio.com/docs/voice/how-share-information-between-your-applications - but as a general-purpose workaround, you could just store the column on the database.
First, make a migration to add the column:
add_column :users, :my_variable, :string
Set this value in the first endpoint:
def first
current_user.update my_variable: "xxxx"
end
Then read it from the second:
def second
# first you would need to load the user, then you can read the value:
my_variable = current_user.my_variable
# you could set the db value to nil here if you wanted
current_user.update my_varible: nil
end
I set the flash message as below in one of my routes
def signup
flash[:is_signup] = true
... redirect_to route1 : route2 // based on some logic, redirect accordingly
end
def route1
// access flash[:is_signup]
flash.discard(:is_signup)
// do something
end
As depicted above, after i set the flash variable, i could redirect_to either the route(route1) that uses this flash variable or another route(route2) that doesn't care about this flash variable at all.
The issue is, when i redirect to route2, and then go on and mind my own business, hitting several routes/actions in the process, when i end up hitting the route1, the flash variable is still there.
I haven't seen anything in the documentation that says it is available until it is read. Is this the case? or am i doing something wrong?
Thanks in Advance
I'm seeing this as well (rails 4.2.11), and agree: no docs indicate access of flash should be necessary.
But, if I have a page that sets flash[:blah] = 'applesauce' and consumes the flash (e.g., puts flash[:blah]) on the next request, that key is not present in the following request. If I don't, it will linger through request after request until I hit a one where I check the flash.
My workaround is this:
In application_controller.rb
class ApplicationController < ActionController::Base
before_action :touch_flash
#...
def touch_flash
flash
end
end
This act of referencing flash appears to be enough to trigger a discard at end of the request (but doesn't interfere with any actual access later in the request). Next request, it's gone as expected.
I'm working on an app that uses state_machine. I want to call a transition method but not persist the change, so that I have an opportunity to check whether the proposed change is authorized. Eg:
def some_controller_action
# ...
account.close # but don't save...
authorize account # will explode if current_user may not do this
if account.save ....
How can I do this?
Pass false
Eg:
account.close(false) # does not save
This isn't exactly documented, but I found it here.
I can get this devise_ldap_authenticatable working just fine when I don't care about what groups they are, it either connects to ldap and authenticates the user signing in under devise or doesn't. But I want to let only certain members that are apart of one or several specific groups in. I had a post on this question here:
Checking group membership in rails devise ldap gem, is it in the yaml?
(the gem for completeness sake is this one: https://github.com/cschiewek/devise_ldap_authenticatable)
Got to thinking I am asking the wrong question. I think I want to know how in devise (and the devise_ldap_authenticatable is the data stored where perhaps I can peek at my array of memberOf's myself and check the groups for myself in code, and then at that time don't let them in. Is there anywhere on the net that's hows this? My googling has turned up nothing but not being a ldap or devise pro I am guessing my terms suck.
I am sure I just might of missed the how to do this, closest I can see that might help (Though in its form as I read it makes little sense to me is the part on the readme here:
https://github.com/cschiewek/devise_ldap_authenticatable/blob/master/README.md
about querying ldap, is this the case?)
You could do this with a callback or validation on the User (or equivalent) model.
before_create :user_is_not_member_of_specified_group?
private
def user_is_not_member_of_specified_group?
member_of = Devise::LdapAdapter.get_ldap_param(self.username,"memberOf")
test member_of
end
where test is a method that returns true/false based on your conditions for the member groups.
The Devise::LdapAdapter.get_ldap_param(self.username,"memberOf") is a method from devise_ldap_authenticatable that will return an array of member groups. You'll want to run your group testing on this array.
If you use a validation you could specify an error message for users that failed the test. Hope this helps.
EDIT
Another way to handle this would be to let your gem handle the redirection and error messages by monkeypatching the authorized? method in Devise::LdapAdapter::LdapConnect (https://github.com/cschiewek/devise_ldap_authenticatable/blob/master/lib/devise_ldap_authenticatable/ldap_adapter.rb). It would look like:
Devise::LdapAdapter::LdapConnect.class_eval do
def user_group_test
member_of = self.ldap_param_value("memberOf")
test member_of # your group test method
end
def authorized?
DeviseLdapAuthenticatable::Logger.send("Authorizing user #{dn}")
if !user_group_test
DeviseLdapAuthenticatable::Logger.send("Not authorized because custom authentication failed.")
return false
elsif !authenticated?
DeviseLdapAuthenticatable::Logger.send("Not authorized because not authenticated.")
return false
elsif !in_required_groups?
DeviseLdapAuthenticatable::Logger.send("Not authorized because not in required groups.")
return false
elsif !has_required_attribute?
DeviseLdapAuthenticatable::Logger.send("Not authorized because does not have required attribute.")
return false
else
return true
end
end
end
You would want to put this in a custom initializer file in config/initializers.
Here is my situation, I use devise to allow users to create account on
my site and manage their authentication.
During the registration process I allow customers to change some
options, leading to an actually different account being created but
still based on the same core user resource.
I would like to choose not to send a confirmation email for some of
those account types. I don't care if the account do not get confirmed
and user cannot log in, that's ok, no pb with that.
How would I go about doing that ?
Thanks,
Alex
Actually it's quite easy once I dig a little deeper.
Just override one method in your User model (or whatever you are using):
# Callback to overwrite if confirmation is required or not.
def confirmation_required?
!confirmed?
end
Put your conditions and job's done !
Alex
If you just want to skip sending the email but not doing confirmation, use:
# Skips sending the confirmation/reconfirmation notification email after_create/after_update. Unlike
# #skip_confirmation!, record still requires confirmation.
#user.skip_confirmation_notification!
If you don't want to call this in your model with a callback overwrite this method:
def send_confirmation_notification?
false
end
You can also simply add the following line of code in your controller before creating the new user:
#user.skip_confirmation!
I don't know if Devise added this after the other answers were submitted, but the code for this is right there in confirmable.rb:
# If you don't want confirmation to be sent on create, neither a code
# to be generated, call skip_confirmation!
def skip_confirmation!
self.confirmed_at = Time.now
end
I was able to do something similar with the functions:
registrations_controller.rb
def build_resource(*args)
super
if session[:omniauth] # TODO -- what about the case where they have a session, but are not logged in?
#user.apply_omniauth(session[:omniauth])
#user.mark_as_confirmed # we don't need to confirm the account if they are using external authentication
# #user.valid?
end
end
And then in my user model:
user.rb
def mark_as_confirmed
self.confirmation_token = nil
self.confirmed_at = Time.now
end