I am looking to MD5 hash a email address prior to outputting from a Rails Model. Currently my modal looks like so:
class Comment < ActiveRecord::Base
belongs_to :post
attr_accessible :body, :name, :reply, :email
validates_presence_of :body, :name
def gravator
require 'digest/md5'
email_address = self.email.downcase
# create the md5 hash
hash = Digest::MD5.hexdigest(email_address)
# compile URL which can be used in <img src="RIGHT_HERE"...
self.email = "http://www.gravatar.com/avatar/#{hash}"
end
end
I'm wondering what the best way to convert the email field to the outputted URL from the gravator method.
Thanks for any help!
Rather than hashing it every time, create a new field in the database that contains the hashed value.
Create a gravator field and assign it on before_save. This will speed things up and won't call the database each time it is displayed.
class Comment < ActiveRecord::Base
belongs_to :post
attr_accessible :body, :name, :reply, :email
validates_presence_of :body, :name
before_save :set_gravator
def set_gravator
require 'digest/md5'
email_address = self.email.downcase
# create the md5 hash
hash = Digest::MD5.hexdigest(email_address)
# compile URL which can be used in <img src="RIGHT_HERE"...
self.gravator = "http://www.gravatar.com/avatar/#{hash}"
end
end
Related
I currently have a Check_In model that belongs_to my Subscriber model which has_many Check_Ins.
The Subscriber model takes in a phone_number along with some other attributes and the Check_In model take in a "visit_amount" as an integer.
After a person Subscribes with the view form I want the option for them to Check_In by placing their subscriber phone_number in a Check_In view form.
After they place their number in the form the Check_In model will + 1 to the "visit_amount" on that particular Subscriber.
I'm new to rails and I'm wondering if this is possible? if so, how should I go about implementing this feature? I will show my current code for reference.
MODEL
class Subscriber < ActiveRecord::Base
has_many :check_ins
validates :first_name, presence: true
validates :last_name, presence: true
validates :email, presence: true
validates :phone_number, presence: true
def date_joined
created_at.strftime("%-m/%-d/%-y")
end
def expiration_date
(created_at + 1.year).strftime("%-m/%-d/%-y")
end
end
~
class Check_In < ActiveRecord::Base
belongs_to :subscriber
end
I have basic controllers and views. Everything is really basic at this point but this is the main feature that I need for this app.
Here is the create action for your use case.
class CheckInsController < ApplicationController
def create
# First, create a CheckIn that belongs to the current_subscriber
#check_in = CheckIn.new.tap do |check_in|
check_in.subscriber = current_subscriber
end
# Then check if submitted phone number is correct
if params[:phone_number] == current_subscriber.phone_number
#check_in.save
else
# do something when the verification failed
end
end
# more code...
end
Hope that helps.
If you do not have authentication in the app, you can do
def create
subscriber = Subscriber.find_by(phone_number: params[:phone_number])
if subscriber
CheckIn.create(subscriber: subscriber)
else
# some code
end
end
Last, your form should look like :
<%= form_tag check_ins_path do %>
<%= label :phone_number %>
<%= text_field_tag :phone_number %>
<%= submit_tag 'Check In' %>
<% end %>
Do not use form_for #check_in or your params will look like { check_in: { phone_number: '1234-56-7890' } and you will have to fetch params[:check_in][:phone_number] in your create action, which feels uncomfortable to me(check ins do not have phone numbers).
:counter_cache can do what you want. add a new field call count_of_check_ins in the table subscribers, then update the class definition as follow:
class Subscriber < ActiveRecord::Base
has_many :check_ins
end
class Check_In < ActiveRecord::Base
belongs_to :subscriber, counter_cache: :count_of_check_ins
end
the count_of_check_ins will be updated automatically.
On the page where you want the form to accept the users input for a checkin put the following in its corresponding action (typically would be the CheckinsController, new action):
def new
#checkin = Check_In.new
end
def create
user = current_user #assuming u have a current user method
#checkin = user.check_in.new(checkin_params)
if #checkin.save
# ...
end
end
private
def checkin_params
params.require(:check_in).permit(:phone_number)
end
Then in your model CheckIn you need to add accepts_nested_attributes_for so it allows the phone number to be added.
I am using the Active Model Serializer gem for my application. Now I have this situation where a user can have an avatar which is just the ID of a medium.
I have the avatar info saved into Redis. So currently what I do to show the avatar at all in the serialized JSON, is this:
class UserSerializer < ActiveModel::Serializer
include Avatar
attributes :id,
:name,
:email,
:role,
:avatar
def avatar
Medium.find(self.current_avatar)[0]
end
#has_one :avatar, serializer: AvatarSerializer
has_many :media, :comments
url :user
end
I query Redis to know what medium to look for in the database, and then use the result in the :avatar key.
Down in the code there is also a line commented out, that was the only way I found on the https://github.com/rails-api/active_model_serializers/ page about using a custom serializer for something inside of serializer.
So to get to my problem. Right now the :avatar comes just like it is in the database but I want it to be serialized before I serve it as JSON.
How can I do that in this case?
You need to serialize Avatar Class:
class Avatar
def active_model_serializer
AvatarSerializer
end
end
Then you just use this way:
class UserSerializer < ActiveModel::Serializer
include Avatar
attributes :id,
:name,
:email,
:role,
:avatar
def avatar
# Strange you query another object
avatar = Medium.find(object.current_avatar).first
avatar.active_model_serializer.new(avatar, {}).to_json
end
has_many :media, :comments
url :user
end
According to the docs if you want a custom serializer you can just add:
render json: avatar, serializer: AvatarSerializer
or whatever your serializer name could be, here are the docs:
https://github.com/rails-api/active_model_serializers/blob/v0.10.6/docs/general/serializers.md#scope
I would like to add a modified variable to my index.json.
views/posts/index.json.builder
json.array!(#posts) do |post|
post[:image_th] = post[:image].reverse.split('.', 2).join(".s").reverse
#this is the new line above
json.extract! post, :id, :title, :datum, :body, :image
#json.url post_url(post, format: :json)
end
So itt adds an 's' before ".jpg" in the string.
This gives error:
can't write unknown attribute `image_th'
How to add a field to index.json without creating a migration and accessing it from the database?
Try:
class Post < ActiveRecord::Base
# ...
def image_th
image.reverse.split('.', 2).join(".s").reverse
end
end
And then:
json.extract! post, :id, :title, :datum, :body, :image_th
EDIT:
Also the method would be probably slightly cleaner with:
def image_th
image.sub(/\.[^\.]+$/, 's\0')
end
If you don't need to persist it, you can use an attr_accessor :image_th in your Post model:
class Post < ActiveRecord::base
attr_accessor :image_th
end
Anyway that claims more to be a method than a field in your model
I want to have a 'contact person' form that allows a user to enter their Personal and Work email at the same time.
I can imagine two ways of doing this but am not sure they're optimal and may be missing a Rails way of doing so:
Have the nested form create the email model twice, but add a flag for :position to identify them. (Hidden field to do so?)
Set up a delegate that maps :personal_email and :work_email to the Email model such that the model handles them separately.
Something else?
Currently I have emails set up like this:
class Individual < ActiveRecord::Base
attr_accessible :first_name, ...
has_many :emails
#delegate :personal_email, :to => :email, :allow_nil => true
end
class Email < ActiveRecord::Base
attr_accessible :email_address, :owner_id, :owner_klass, :position, :verified, :email_type
belongs_to :individual
# WIP Returns 'primary' email for a user
def personal_email
end
end
In a rails model, is it possible to do something like
class Example < ActiveRecord::Base
#associations
validates_presence_of :item_id, (:user_id OR :user_email)
#functions
end
Where the model has 3 columns of :item_id, :user_id, and :user_email?
I want the model to be valid as long as I have a :user_id or a :user_email.
Idea being that if the item is recommended to a person who isn't currently signed up, it can be associated via email address for when the recommended person signs up.
Or is there a different method that I can use instead?
One approach is to wrap those fields as a virtual attribute, say:
class Example < ActiveRecord::Base
validates_presence_of :referral
def referral
user_id || user_email
end
end
or you can just throw a custom validate validation method. See custom validations on the Rails API
If both user_id and user_email come from another model, perhaps it's better to add the association instead
class Example
belongs_to :user
validates_associated :user
before_validate :build_user_from_id_or_email
def build_user_from_id_or_email
# ... Find something with the parameters
end
end
validates_presence_of :item_id
validates_presence_of :user_id, :if => Proc.new{ |x| x.user_email.blank? }
validates_presence_of :user_email, :if => Proc.new{ |x| x.user_id.blank? }