Rails: How to show if value already exists in database - ruby-on-rails-3

My app imports products from a Shopify store. It needs to cater for products that have previously been imported in to my apps database and also show any new products that have been added to the Shopify store since the last import.
My view is:
# All new products in Shopify
<% #products.each do |product| %>
<tr>
<td><%= product.id %></td>
<td><%= product.title %></td>
</tr>
<% end %>
# All existing products in my app
<% #myproducts.each do |myproduct| %>
<tr>
<td><%= myproduct.id %></td>
<td><%= myproduct.title %></td>
</tr>
<% end %>
The part of ProductsController controller responsible grabbing these is:
#products = ShopifyAPI::Product.find(:all)
#myproducts = Product.where.not(id: nil)
The issue is that the first each loop displays all products from the Shopify store, including those products already in #myproduct.each do loop. So we end up having a lot of double-ups.
I need #products.each loop to only display products where product.id does not already exist as myproduct.id.
Should I be using an if statement in my view or some conditions in #products = ShopifyAPI::Product.find(:all) ?

Yes!
ShopifyAPI::Product.find(:all) will fetch all the products in the store.
so you need to add the condition into your controller.
Option1
#myproducts = Product.where.not(id: nil).select(:id, :title)
#products = ShopifyAPI::Product.find(:all)
myproducts_titles = #myproducts.map(&:title)
#products = #products.reject do |product|
myproducts_titles.include? product.title
end
Option2
#myproducts = Product.where.not(id: nil).select(:id, :title)
myproducts_titles = myproducts.map(&:title)
#products = ShopifyAPI::Product.find(:all)
products_titles = #products.map(&:title)
newproducts_titles = products_titles - myproducts_titles
#products = #products.select do |product|
newproducts_titles.include? product.title
end
I'm not sure whether which options are much faster

I tried something myself. I introduced:
#productIds = Product.pluck(:product_id)
Then a new loop:
#products.delete_if do |product|
if product.id.in?(#productIds)
true
end
end
Seems to do this trick for now.

Related

Rails. how to display the data by column name

I use Rails 4.
I use structure
#users = ActiveRecord::Base.connection.execute("SELECT * FROM users")
#users.each do |row| %>
puts user[0] # id--> 1,2,3,4,5,6
end
#users.fields do |field| %>
puts field.name # --> id, login, password.....
end
how to display the data by column name?
for example
#users.first.field['id']
ActiveRecord::Base.connection.execute( will run the sql but not return anything (or return nil, more accurately). To load the records into memory do
#users = User.all
You don't describe what you want very well. If you literally want "1,2,3,4,5,6" you could do
#users.map(&:id).join(",")
if you wanted, for example, to do a table showing all the user data you could do (in your view)
<% cols = User.column_names %>
<table>
<thead>
<tr>
<% cols.each do |col| %>
<th><%= col %></th>
<% end %>
</tr>
</thead>
<tbody>
<% #users.each do |user| %>
<tr>
<% cols.each do |col| %>
<td><%= user.send(col) %></td>
<% end %>
</tr>
<% end %>
</tbody>
</table>
Like i say i don't know if this is what you actually want to do. Your requirements are a very messy and very vague.
EDIT
If you want to load data out of the database without using an AR model then you can do
#users = ActiveRecord::Base.connection.select_all("select * from users")
this will give you an array of hashes like this
[{"id" => "1", "name" => "foo", "bar" => "baz"}, {"id" => "2", "name" => "chunky", "bar" => "bacon"}, .... ]
which you could then access like
user = #users.first #you've got a hash now
aname = user["name"]

SQL that creates a new table, essentially, but with ActiveRecord

def reports
sql = "select username, email, sign_in_count, current_sign_in_at, \
(select count(*) from foo ft where ft.user_id = u.id and ft.state in ('complete', 'active', 'win', 'lose')) as foo_state, \
(select count(*) from bar where creator_id = u.id and m.state not in ('new','cancelled')) as bar_created, \
from users u where sign_in_count > 0 order by foo_state desc;"
#users = ActiveRecord::Base.connection.execute(sql)
end
So, this query is botched a bit for purposes of showing you something, but not bothering you with the details. This query takes a few different tables, queries them, and returns a new table essentially. I'm using postgreSQL, so this returns a PG::Result object. I can call #users.values to get an array of arrays, but I was wondering if there was a more 'rails-y' way do do this?
I'd like to do something like this in the view:
<%= render partial: 'users/shared/user', collection: #users, as: :user %>
but since it's not an actual ActiveRecord object, I can't seem to do that (although it doesn't throw an error if I try, it just doesn't display anything)
Can ARel accomplish a feat like this? Am I asking too much? Thanks!
For anyone else stumbling upon this... this works to get your info, at least:
<table>
<thead>
<tr>
<% #users.fields.each do |f| %>
<th><%= f %></th>
<% end %>
</tr>
</thead>
<tbody>
<% #users.values.each do |v| %>
<tr>
<% v.each do |a| %>
<td><%= a %></td>
<% end %>
</tr>
<% end %>
</tbody>
</table>

Date field not saved using rails 3.0?

I have an ActiveRecord and when i click on save all records are saved except the date.
My contorller
class UsersController < ApplicationController
def create
puts params[:user]
#user1 = User.new(params[:user])
if #user1.save
saveduser = User.where("fbid = ?",params[:user][:fbid])
unless saveduser.first.nil?
session[:user] = saveduser.first
end
puts "user saved "
redirect_to "/users/dashboard"
else
puts "error while saving user"
end
end
The view
<h3>User Details</h3>
<%= form_for(#user) do |f| %>
<table>
--some columns
<tr>
<td><%= f.label :state %></td>
<td> <%= f.text_field :state %></td>
</tr>
<tr>
<td><%= f.label :dob %></td>
<td> <%= f.text_field :dob %></td>
</tr>
<%= f.hidden_field :fbid %>
</table>
<%= f.submit %>
<% end %>
<table>
In console when create method is called in UserController . I can see
{"username"=>"xxxx.xx.94", "firstname"=>"xxxx", "lastname"=>"Raxxstogi", "emaild"=>"xx.xxx#gmail.com", "city"=>"Los Angeles", "country"=>"USA", "state"=>"CA", "dob"=>"08/13/1983", "fbid"=>"xxx"}
My DB table column is
dob | date | YES | | NULL |
Where is it going wrong?
Thanks
You are using a text_field in your form to save into a Date type field in the DB. Try instead to use the date helper methods as described here:
http://guides.rubyonrails.org/form_helpers.html#using-date-and-time-form-helpers
Ruby doesn't understand your date format. You can fix this by explicitly parsing the date with Date::strptime, perhaps in the model as a setter method:
class User < ActiveRecord::Base
def dob=(date)
date = Date.strptime(date, '%m/%d/%Y') if date.is_a?(String)
write_attribute(:dob, date)
end
end
I would, however, second jordanpg's recommendation to use the date helpers in Rails, unless you know that the format will be the same every time.
it could be the problem with your date format. You can either configure active record to accept this format or convert your date param to Date object using strftime or something like it

"Undefined method `each' for '2,1':String" when using #partner.products association?

I have a part file where I want to show all my products for a specific partner.
Here's the html.erb:
<% unless #products.nil? %>
<% #products.each do |prod|%>
<tr id="p_<%= prod.id%>">
<td><%= prod.name %></td>
<td><%= prod.price %></td>
<td><%= number_field_tag "product_qty_input[#{prod.id}]", get_offer_product_qty(#offer.id, prod.id),:min => 0, :max => 99 %></td>
<td>X</td>
</tr>
<% end %>
<% end %>
But I keep getting the error: undefined method `each' for "2,1":String
it says it's on this line: <% #products.each do |prod|%>
But I don't see the problem..
Here's my controller:
def select_products
#partner = Partner.find(params[:partner_id])
if params[:id] == "-1"
#offer = nil
else
#offer = Offer.find(params[:id])
end
#select_callback = url_for( #offer.nil? ? new_partner_offer_path(#partner) : [:edit, #partner, #offer] )
#products = #partner.active_products
#num_select = PRODS_PER_OFFER
respond_to do |format|
format.html { render :template => "products/select"}
end
end
You see I have #products = #partner.active_products method, but i changed that to see if it got there, and it's not, must be something before...
I would apreciate any help.
Thanks in advance
UPDATE
Here is the method active_products :
def active_products
self.products.where("active IS NOT NULL AND active = true")
end
It should be returning the object not string
What am I doing wrong?
Thanks #thesis
UPDATE 2
Guys, Thanks a lot for the help, and with the assistence of #thesis I figured it out.
It was actualy something that I haven't thought about before, and it wasn't describe here in the question.
My sessionkeeper helped me keep my form as I selected products in another page!
That was meesing it up!
Your problem is very simple. You have to fix your active_products method, as it returns String. In your case, string is "2,1" but you have to return collection of products, to iterate it with each method.
For additional help, please update your question and add active_products instance method from Partner model.
Do you really have products as numbers "2,1".
#partner.active_products should ideally return ActiveRecord::Relation, hence it should iterate objects of Product class.
Please go through http://guides.rubyonrails.org/
And before that, you may like to search for 'ruby philosophy' and 'rails philosophy'

Include controller methods in emails in a Rails 3 application?

I am trying to email a monthly report which is simple the current month's income compared to the last months.
I have all of that working in my report controller (which references another model called Clinical):
# Clinical income by month report
#clinical_income_by_month = Clinical.select(%q{date_format(transactiondate, '%Y') as year, date_format(transactiondate, '%M') as month, sum(LineBalance) as income})
.where(:payments => 0)
.where('linebalance <> ?', 0)
.where('analysiscode <> ?', 213)
.group(:monthyear)
I then have a partial for the table with the data:
<div class="row">
<div class="twelve columns"><h5>This months income so far is <span style="font-size:1.2em"class="<% if #clinical_income_by_month.first.income >= #clinical_income_by_month.first(:offset => 12).income %>green<% else %>red<% end %> radius label"><%= number_to_currency(#clinical_income_by_month.first.income, :unit => "£", :separator => ".", :delimiter => ",") %></span></h5> <%= #clinical_income_by_month.first.month %> <%= #clinical_income_by_month.first(:offset => 12).year %>'s income was <%= number_to_currency(#clinical_income_by_month.first(:offset => 12).income, :unit => "£", :separator => ".", :delimiter => ",") %>.</div>
</div>
<hr />
<table>
<tr>
<th>Year</th>
<th>Month</th>
<th>Income</th>
</tr>
<% #clinical_income_by_month.each do |c| %>
<tr>
<td><%= c.year %></td>
<td><%= c.month %></td>
<td><%= number_to_currency(c.income, :unit => "£", :separator => ".", :delimiter => ",") %></td>
</tr>
<% end %>
</table>
I would like to be able to pull that partial into my email, or if that's not possible, I would like to show the value of the last income.
<%= #clinical_income_by_month.first.income %>
My email code looks like this:
Finance Report
================================================
<%= number_to_currency(#clinical_income_by_month.first.income) %>
The error I am getting is:
1.9.2-p318 :009 > UserMailer.finance_report().deliver
ActionView::Template::Error: undefined method `first' for nil:NilClass
from /Users/dannymcclelland/Projects/premvet/app/views/user_mailer/finance_report.text.erb:3:in `_app_views_user_mailer_finance_report_text_erb___4501411113534248604_70358523362460'
It works when I pull a value from the standard method:
<%= number_to_currency(Clinical.first.UserID) %>
but not when I call it from the #clinical_income_by_month report I created.
Any pointers would be appreciated!
You need to do something like this:
in user_mailer.rb
def finance_report(clinical_income_by_month)
#clinical_income_by_month = clinical_income_by_month
... # all you had here before
end
And in the controller call it this way:
UserMailer.finance_report(#clinical_income_by_month).deliver
Clearly your #clinical_income_by_month is nil. That means the select query is not returning values as you think it should. This is a model problem. Instead of checking the views, you should fire up the "rails console" and see whether the query returns the values you want.