I'm using Rails to build a simple web app.
I have a form asking users to select a vice category (e.g.: smoking, shopping, drinking coffee, etc.) and how much they spend (value) per day, in euros (unit).
Schema:
create_table "vices", force: :cascade do |t|
t.string "category"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.float "value"
t.string "unit"
t.string "user"
t.string "hobbies"
end
After submitting the form I dynamically show a message:
<%= "Stop #{#vice.category} and you will save #{#vice.value * 365} #{#vice.unit} per year!" %>
Second line:
<%= "Here's what you can buy instead:" %>
After this, I want to show Amazon products that they can buy according to their hobbies.
For example: if you stop smoking you will save 2000 euros a year. Here are drones you can buy instead. And then I show drones from Amazon.
I have been trying to connect to Amazon Product Advertising API using amazon-ecs gem but no luck showing it so far.
I then have a show.json.builder file with this:
json.partial! "vices/vice", vice: #vice
Amazon::Ecs.configure do |options|
options[:AWS_access_key_id] = '[my access key]'
options[:AWS_secret_key] = '[my secret key]'
options[:associate_tag] = '[my associate tag]'
end
res = Amazon::Ecs.item_search('#{#vice.hobbies}', {:response_group => 'Medium', :sort => 'salesrank'})
Is this correct?
How can I show the Amazon results in show.hmtl.erb
This is my first question here on Stack OVerflow. Let me know what else I need to post to expand on the explanation.
Thanks!
Related
I have a Rails 5 app and want to assign some Date (not Datetime) columns of an Advert model.
The model schema is as follows, including 2 Date columns - 'start' and 'end'.
create_table "adverts", force: :cascade do |t|
t.integer "user_id"
t.integer "product_id"
t.date "start"
t.date "end"
t.boolean "expired", default: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
The Advert controller also permits update of these columns,
def advert_params
params.require(:advert).permit(:user_id, :product_id, :start, :end, :expired)
end
I then have a method in the controller that is intended to update an advert.
The route is
post 'update_advert', :on => :collection
The advert record is pulled / created using find_or_initialize.
def update_advert
#advert = Advert.find_or_initialize_by(user_id: advert_params[:user_id], product_id: advert_params[:product_id])
logger.info "checkpoint1"
logger.info advert_params.inspect
logger.info "checkpoint2"
...
end
This gives the following log output,
I, [2020-05-19T12:32:46.947732 #13110] INFO -- : [e741ba19] checkpoint1
I, [2020-05-19T12:32:46.948986 #13110] INFO -- : [e741ba19] <ActionController::Parameters {"user_id"=>1, "product_id"=>1000, "expired"=>false} permitted: true>
I, [2020-05-19T12:32:46.949151 #13110] INFO -- : [e741ba19] checkpoint2
Note the start and end columns are missing, which therefore prevents me from going on to update them.
If I 'show' the record via the standard Rails web interface, I see the fields as expected.
If I pull the record via the JSON api, I see the expected fields.
{"id":4,"user_id":1,"product_id":1000,"start":"2020-05-18","end":"2020-06-18","expired":false}
My question is - why are the start and end columns not returned as part of the find_or_initialize response?
Thanks for reading.
I've been following Railscast 289 tutorial on how to make recurring payments using Paypal.
I got everything working now except that I am now struggling to figure out how am I able to know if the user cancelled their subscription in paypal.
What I've done
I've manage to set the IPN url in the paypal merchant account and everytime someone subscribes it will send me data from paypal to my webhook.
Now I am storing all the parameters that paypal sends me but I am unable to figure out which of the parameters I should be checking in order to know if the user has cancelled their subscription or if it had not enough funds, etc.
At least this is the way I think it works.
I'm using Paypal Recurring Gem
Questions
How do I notice when an user has cancelled their subscription when paypal sends me their IPN to my webhook.
My webhook atm
def create
user_id = Subscription.find_by(paypal_customer_token: params[:payer_id]).user_id
PaymentNotification.create!(params: params, user_id: user_id, user_role_id: params[:item_number], status: params[:payment_status], transaction_id: params[:txn_id])
#user = User.find_by(id: user_id)
if PaymentNotification.last.params[:profile_status] == "Cancelled"
#user.update_attributes(user_role_id: 1)
end
render nothing: true
end
Notice that I don't want to update the users attribute instantly I want to wait until their month subscription has ended.
I'm currently storing their IPN call in PaymentNotification table.
create_table "payment_notifications", force: :cascade do |t|
t.text "params"
t.integer "user_role_id"
t.string "status"
t.string "transaction_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id"
end
Also, what is the best way to check for these parameters in order to take action to users who haven't paid or have cancelled their subscription?
I have another table which stores the subscriptions
create_table "subscriptions", force: :cascade do |t|
t.integer "user_role_id"
t.integer "user_id"
t.string "paypal_customer_token"
t.string "paypal_recurring_profile_token"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
user_role being in this case the plan they are subscribing.
IPN ensures that you're notified when there's any change to your transactions, from a recurring payment perspective, when your customer cancels the profile, an event triggered POST-Back will be sent to your IPN listener.
A sample raw POST-Back message of profile cancelation will be like this,
payment_cycle=Daily &txn_type=recurring_payment_profile_cancel &last_name=US &next_payme
nt_date=N/A &residence_country=US &initial_payment_amount=0.00 ¤cy_code=USD &t
ime_created=19:25:09 Sep 24, 2015 PDT &verify_sign=AgUGxKs4vGiEqeit6IyHkIjDJVpeAqCMRVC4wh9CZYotn
Jqrr-3oWsFe &period_type= Trial &payer_status=verified &test_ipn=1 &tax=0.00 &pa
yer_email=USP#email.com &first_name=Payer &receiver_email=USM#email.com &payer_id=8FMFQ2
KVYYHTY &product_type=1 &shipping=0.00 &amount_per_cycle=2.00 &profile_status=Cancel
led &charset=gb2312 ¬ify_version=3.8 &amount=2.00 &outstanding_balance=0.00 &recurring_payment_id=I-30FKJ55UV1RW &product_name=RP BA Test &ipn_track_id=65583f3a80f10
How would you be able to notice when a cancelation happens?
Read the parameter txn_type in the IPN message, and determine event type with it (in your case, the event type would be recurring_payment_profile_cancel, find more details on txn_type list in the PayPal IPN Variables)
Reconcile the profile/subscription with your database entry and take action
Match the recurring_payment_id=I-30FKJ55UV1RW from the IPN message with your pre-stored database entry paypal_recurring_profile_token, and take action to update the user_role_id field. (Either stop the subscription instantly or update/set a new expiration date based on your business mode)
So, I'm using Rails 4, and I have an enum column on my "Sales_Opportunity" object called pipeline_status - this enables me to move it through a sales pipeline (e.g. New Lead, Qualified Lead, Closed deal etc). This all works fine. I'm able to find the number of sales_opportunities that a company has by status through using the following:
<%= #company.sales_opportunities.where(pipeline_status: 3).count %>
This all works fine. What I want to do is to find all sales_opportunities that have the pipeline_status of "closed_won" (enum value of 4 in my app) and sum the value of each won deal (so I can represent the total value of the customer based on the deals that are won in the system). A Sales_Opportunity in my model has a sale_value field, so I tried:
<%= #company.sales_opportunities.where(pipeline_status: 4).each.sale_value.sum %>
which returns the following error:
undefined method `sale_value' for #<Enumerator:0x007f9b87a9d128>
This is probably a trivial error but I can't for the life of me figure out what's going on. Is there where statement returning the enumerator or the sales_opportunity objects with that enumerator? Any help would be gratefully appreciated.
If it helps here are the fields in my sales_opportunities table:
create_table "sales_opportunities", force: true do |t|
t.datetime "close_date"
t.integer "user_id"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "pipeline_status", default: 0
t.string "opportunity_name"
t.integer "company_id"
t.decimal "sale_value", precision: 15, scale: 2, default: 0.0
end
A Sales_opportunity belongs_to a Company Object and a User Object, if that makes any difference.
use aggregate function sum
<%= #company.sales_opportunities.where(pipeline_status: 4).sum(:sale_value) %>
Other possibility is to use
<%= #company.sales_opportunities.where(pipeline_status: 4).pluck(:sale_value).reduce(0, :+) %>
I have just changed a column (called time) from t.string to t.datetime and then dropped and re-created the database and run the migration.
I have a script set to run every minute that scrapes information from a remote website and then adds the information to new records based on the time column that I adjusted to be a datetime rather than string.
# Add each row to a new call record
page = agent.page.search("table tbody tr").each do |row|
next if (!row.at('td'))
time, source, destination, duration = row.search('td').map{ |td| td.text.strip }
call = Call.find_or_create_by_time(time)
call.update_attributes({:time => time, :source => source, :destination => destination, :duration => duration})
end
Since changing the time column to integer the script doesn't seem to be importing any information at all. I wondered if there is an extra step that I need to do to make this work again?
My schema looks like this:
create_table "calls", :force => true do |t|
t.string "source"
t.string "duration"
t.datetime "time"
t.string "destination"
t.string "recording"
t.string "cost"
t.datetime "created_at"
t.datetime "updated_at"
end
In this part
time, source, destination, duration = row.search('td').map{ |td| td.text.strip }
call = Call.find_or_create_by_time(time)
you get time variable as a string, and trying to find_by it. I think smth like
call = Call.find_or_create_by_time(Time.parse(time))
should do the trick
This might seem like a duplicate question, but I can't find any information on this. I want to show the results from a remotely acquired json array excluding certain results by comparing them to a local table. I have a gallery model with:
t.integer :smugmug_id
t.string :smugmug_key
t.integer :category_id
t.string :category_name
t.string :description
t.integer :highlight_id
t.string :highlight_key
t.string :highlight_type
t.string :keywords
t.string :nicename
t.integer :subcategory_id
t.string :subcategory_name
t.string :title
t.string :url
The data for this model gets populated by a rake task that connects to the smugmug api (json) and stores the data locally. I'm trying to create a view that shows all the smugmug galleries that are not stored locally.
Here's what I've tried so far, but it's not excluding the locally stored galleries like I thought it would.
def self.not_stored
smugmug_list = Smug::Client.new.albums(heavy = true)
gallery_list = Gallery.select(:smugmug_id)
smugmug_list.each do |smugmug|
smugmug unless gallery_list.include? smugmug.id
end
end
Hopefully this makes sense. I'm getting a json array of galleries, and I want to display that array excluding results where the album id matches the smugmug_id of any of my locally stored records.
Quick edit: I'm using an adaptation of this gem to connect to the smugmug api.
Just use the difference operator.
General Example:
ruby-1.9.2-p136 :001 > [3,2,1] - [2,1]
=> [3]
So you would have:
smugmug_list.collect{|e| e.id} - gallery_list
Enumerable#collect will turn the smugmug_list into a list of id's. From there, you can do the difference operator, which will return all the id's of all the smugmug galleries that are not stored locally.
Another option to maintain the list of galleries:
smugmug_list.select{|e|!gallery_list.include?(e.id)}