Custom updated_at for a specific field/attribute in rails - ruby-on-rails

I currently have a method that increments an attribute on the Subscriber. It's visit attribute that takes in a int. My question is - Can I find that Subscriber that last had their visit attribute updated? In the console it would look something like this - Subscriber.find("visit +=1").last <- completely wrong BTW, but I assume it would look kinda like that? Does anybody know how I can call this in the console?? Any help would be great.
Controller Method:
def visit
#subscriber = Subscriber.find_by(params[:phone_number])
if #subscriber
#subscriber.visit ||= 0
#subscriber.visit += 1
#subscriber.save
flash[:notice] = flash[:notice] = "Thank You #{#subscriber.first_name}. You have #{#subscriber.days_till_expired} until renewal"
redirect_to subscribers_search_path(:subscriber)
else
render "search"
end
end
As you can see I would like to call the Subscriber who last used this method to update the visit attribute on their object. Let me know if you need more info.

You can always get the last updated item like this:
Subscriber.order('updated_at desc').first
But :updated_at will update even if anything other than :visit is updated. So you have to write a little migration to add a custom field which will do the work for us.
rails g migration AddLastVistedToSubscriber last_visited:datetime
Run rake db:migrate to add :last_visited to our table. Now we need to update that field whenever we're doing +1 to :visit.
def visit
#subscriber = Subscriber.find_by(params[:phone_number])
if #subscriber
#subscriber.visit ||= 0
#subscriber.visit += 1
if #subscriber.save
#subscriber.touch(:last_visited) #this will update the last_visited with the update time
flash[:notice] = flash[:notice] = "Thank You #{#subscriber.first_name}. You have #{#subscriber.days_till_expired} until renewal"
redirect_to subscribers_search_path(:subscriber)
end
else
render "search"
end
end
Now we can search easily which subscriber's :visit was incremented last.
Subscriber.order('last_visited desc').first

Related

Active Record: Adding "visit" counter on the model

I currently have a Subscriber model that takes in a "phone_number" and a "visit" attribute that is an integer. I want to set up a "check in" view form that will have a subscriber type in their phone_number and it will say if phone_number exists? add 1 to the visit attribute. So it will run a sql query and see if that number is in the database.
To be more clear I have to break the REST actions because the create action is already taken for the new subscribers. I'm pretty new to rails and I'm having a super hard time figuring this feature out. I'm curious if this is possible and how I should go about implementing this?
Here is my controller at the moment:
class SubscribersController < ApplicationController
def index
#subscriber = Subscriber.all
end
def new
#subscriber = Subscriber.new
end
def create
#subscriber = Subscriber.create(subscriber_params)
if #subscriber.save
flash[:success] = "Subscriber Has Been successfully Created"
redirect_to new_subscriber_path(:subscriber)
else
render "new"
end
end
def visit
end
private
def subscriber_params
params.require(:subscriber).permit(:first_name, :last_name, :email, :phone_number)
end
end
Something along those lines?
def visit
subscriber = Subscriber.find_by_phone_number(params[:phone_number])
if subscriber
subscriber.visit += 1
subscriber.save
end
end
Make sure that the default value (via DB/Migration) for visit is set to 0.
You don't need to break REST style controller though. You can create another controller which does that check. For example something like:
class Subscriber::VisitController < ApplicationController
def create
# code here
end
end

undefined local variable or method `days_till_expired'

Currently I have a method called days_till_expired defined in my subscriber model. I'm trying to call it in the controller but it doesn't seem to be working? I must be missing something obvious because this should be a simple implementation. I'll post my code for clarity.
MODEL METHOD:
def days_till_expired
((created_at + 1.year) - DateTime.now).to_i / 1.day
end
CONTROLLER:
def visit
#subscriber = Subscriber.find_by_phone_number(params[:phone_number])
if #subscriber
#subscriber.visit =+ 1
#subscriber.save
flash[:notice] = "Thank You! You have #{days_till_expired} until renewal"
redirect_to subscribers_search_path(:subscriber)
else
render "search"
end
end
As you can see I'm simple trying to call the method with interpolation inside the flash notice but I keep getting this ERROR:
You are not calling to the methods, if you have days_till_expired on your model you forgot to use your model #subscriber.days_till_expired
flash[:notice] = "Thank You! You have #{#subscriber.days_till_expired} until renewal"
If I were you, I would try to move that counter logic to the model.

Create view form that updates attributes - Rails

I currently have a basic controller and model that creates a Subscriber with the normal attributes(name, email, phone, etc...), but I also have a visit attribute on the Subscriber. So I have a form that's rendered with the "new" action and save the input with the create action. << VERY BASIC >> The new feature I want to implement is create a new form that takes in only a phone_number and when the number is entered it update the visit attribute on the subscriber that that corresponds with that number. right now I'm struggling trying to figure this out with just one controller. I'll show my current controller and hopefully that will help for clarity.
CONTROLLER
class SubscribersController < ApplicationController
def index
#subscriber = Subscriber.all
end
def new
#subscriber = Subscriber.new
end
def create
#subscriber = Subscriber.create(subscriber_params)
if #subscriber.save
flash[:success] = "Subscriber Has Been successfully Created"
redirect_to new_subscriber_path(:subscriber)
else
render "new"
end
end
def visit
#subscriber = Subscriber.find_by_phone_number(params[:phone_number])
if #subscriber
#subscriber.visit += 1
#subscriber.save
redirect_to subscribers_visits_new_path(:subscriber)
else
render "new"
end
end
end
As you can see in the visit action I'm trying to implement this feature but I'm not sure where to go from here?
I suppose your search page has a form where you type the number you want to search for. And the request comes to visit action, where you'll increment the +1 to the visit count and then show the details of the number(subscriber).
def visit
#Comes request from search action
#subscriber = Subscriber.find_by_phone_number(params[:phone_number])
if #subscriber
#subscriber.visit += 1
#subscriber.save
redirect_to subscriber_path(#subscriber)
#It will show the details
else
flash[:alert] = "Didn't find with that number. Search again."
render :action => :search
end
end
Update:
Search logic
def search
#will render search.html.erb by convention
end
Inside search.html.erb
<%= form_tag({controller: "subscribers", action: "visit"}, method: "get") do %>
<%= text_field_tag :phone_number %>
<%= submit_tag "Submit" %>
<% end %>
So this will send params to visit action, and after incrementing it will render show method. Hope this helps. Let me know if there is anything.

Validation for datetime

I have problem with validation in my project. I need to validate datetime when saving reservation.
It showing message "This date is reserved." but always create new reservation :(
It can be 3 identical datetime values and not more. Where I have problem in my code?
(I am learning RoR, so, please, be patient. :)
def create
#reservation = Reservation.create!(reservation_params)
#check_count = Reservation.select(:date).where('date = ?', #reservation.date).count
if #check_count <= 3
if #reservation.save!
ReservationMailer.new_service(#reservation).deliver
flash[:success] = "Successfully created reservation."
redirect_to root_path
else
render 'new'
end
else
flash[:error] = "This date is reserved."
render 'new'
end
end
when you do
#reservation = Reservation.create!(reservation_params)
it will create the object and save it before your condition is checked. you should do
#reservation = Reservation.new(reservation_params)
this way it will only initialise it and not save unless your condition is met ie #check_count <= 3
and then when you do .save on it. it will be saved.

how do I make changes to inpus from edit/update in Rails?

I have he following code in my update action for a Controller. The code works when in the create, but doesn't seem to kick in under update:
def update
#contact = Contact.find(params[:id])
# bug, why isn't this working?
unless #contact.fax.empty?
#contact.fax = "1" + Phony.normalize(#contact.fax)
end
unless #contact.phone.empty?
#contact.phone = "1" + Phony.normalize(#contact.phone)
end
if #contact.update_attributes(params[:contact])
flash[:notice] = "Successfully updated contact."
redirect_to #contact
else
render :action => 'edit'
end
end
these should be in your model. FAT model, SKINNY controller:
# contact.rb
...
# may need require 'phony' and include Phony
before_save :prep
def prep
self.fax = 1+Phony.normalize(self.fax) unless self.fax.empty? || (self.fax.length == 11 && self.fax[0] == 1)
self.phone = 1+Phony.normalize(self.phone) unless self.phone.empty? || (self.phone.length == 11 && self.phone[0] == 1)
end
...
Edit:
As I mentioned in my comment, it's better in terms of storage and efficiency and indexing to store as a bigint unsigned in your database and add the prettiness to the numbers in a method. This way, your site is always normalized (no two phone numbers will ever look different because they are formatted 'on the fly').
# sample methods
def phony
str = self.phone.to_s
"#{str[0..2]}-#{str[3..5]}-#{str[6..10]}"
end
# use a similar method for faxing, but I'll write
# this one differently just to show flexibility
def faxy
str = self.fax.to_s
"+1 (#{str[0..2]}) #{str[3..5]}-#{str[6..10]}"
end
you never call save on #contact in your unless blocks, so your call to #contact.update_attributes(params[:contact]) undoes any change you made in those blocks (because those keys in the params hash correspond to empty values).
def update
#contact = Contact.find(params[:id])
if #contact.update_attributes(params[:contact])
#contact.update_attributes(:fax => "1" + Phony.normalize(#contact.fax)) unless #contact.fax.empty?
#contact.update_attributes(:phone => "1" + Phony.normalize(#contact.phone)) unless #contact.phone.empty?
flash[:notice] = "Successfully updated contact."
redirect_to #contact
else
render :action => 'edit'
end
end
You could use update_attribute but that bypasses validation.
You could also use a before_save callback in the Contact class, but you would have to check if the phone or fax are already "normalized."

Resources