Not able to display attachement variant in rails react - ruby-on-rails

I have a product image modal
class ProductImage < ApplicationRecord
belongs_to :product
has_many_attached :images do |attachable|
attachable.variant :thumb, resize_to_limit: [100, nil]
end
def attachement_path
Rails.application.routes.url_helpers.rails_representation_url(
images.first, only_path: true
)
end
def attachement_thumb_path
Rails.application.routes.url_helpers.rails_representation_url(
images.first.variant(:thumb).processed, only_path: true
)
end
end
It perfectly generates attachement_path and display the Image but in case of attachement_thumb_path
It throws the following errors
ActiveStorage::Blob Create (0.4ms) INSERT INTO "active_storage_blobs" ("key", "filename", "content_type", "metadata", "byte_size", "checksum", "created_at", "service_name") VALUES ($1, $2, $3, $4, $5, $6, $7, $8) RETURNING "id" [["key", "uk368qdr9oq73hdg13mdkicpdwb6"], ["filename", "look15.jpg"], ["content_type", "image/jpeg"], ["metadata", "{\"identified\":true}"], ["byte_size", 14510], ["checksum", "f8/qGVxgNbeK3YZ7t/e/HQ=="], ["created_at", "2022-10-26 11:38:41.592281"], ["service_name", "local"]]
ActiveStorage::Attachment Create (0.8ms) INSERT INTO "active_storage_attachments" ("name", "record_id", "record_type", "blob_id", "created_at") VALUES ($1, $2, $3, $4, $5) RETURNING "id" [["name", "image"], ["record_id", nil], ["record_type", "ActiveStorage::VariantRecord"], ["blob_id", "495f44bb-1b19-4279-8331-d7c8d86758f8"], ["created_at", "2022-10-26 11:38:41.593878"]]
TRANSACTION (0.2ms) ROLLBACK
/Users/apple/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/activerecord-7.0.4/lib/active_record/connection_adapters/postgresql_adapter.rb:768:in `exec_params': PG::NotNullViolation: ERROR: null value in column "record_id" of relation "active_storage_attachments" violates not-null constraint (ActiveRecord::NotNullViolation)
DETAIL: Failing row contains (49bcc6c0-4167-42f4-8687-a245847798ad, image, null, ActiveStorage::VariantRecord, 495f44bb-1b19-4279-8331-d7c8d86758f8, 2022-10-26 11:38:41.593878).
/Users/apple/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/activerecord-7.0.4/lib/active_record/connection_adapters/postgresql_adapter.rb:768:in `exec_params': ERROR: null value in column "record_id" of relation "active_storage_attachments" violates not-null constraint (PG::NotNullViolation)
DETAIL: Failing row contains (49bcc6c0-4167-42f4-8687-a245847798ad, image, null, ActiveStorage::VariantRecord, 495f44bb-1b19-4279-8331-d7c8d86758f8, 2022-10-26 11:38:41.593878).
irb(main):003:0>
If I remove the null: false validation from record column of active_storage_attachments table everything works perfectly But since this table is generated by action storage I dont want to modify it.

Related

Preserving the order of an array when using .where in Rails

I am passing an array of ids to a .where in Rails, but the way it's returned doesn't preserve the order. For example, here's the array:
2.5.1 :043 > company_ids
=> [83, 79, 52, 44, 82]
I am looking for all pages that have those company IDs, but returned in the order of those company IDs that were provided. This is the result if I try to compare:
2.5.1 :044 > Page.where(company_id: company_ids).pluck(:company_id)
(1.1ms) SELECT "pages"."company_id" FROM "pages" WHERE "pages"."company_id" IN ($1, $2, $3, $4, $5) [["company_id", 83], ["company_id", 79], ["company_id", 52], ["company_id", 44], ["company_id", 82]]
=> [83, 82, 52, 44, 79]
I ran across this stackoverflow post (ActiveRecord.find(array_of_ids), preserving order) that seems to provide a solution, but it doesn't work for me. When trying to use Page.where(company_id: company_ids).order("field(company_id, #{company_ids.join ','})") as suggested in the stackoverflow post, I get the following error:
2.5.1 :042 > Page.where(company_id: company_ids).order("field(company_id, #{company_ids.join ','})")
Page Load (2.0ms) SELECT "pages".* FROM "pages" WHERE "pages"."company_id" IN ($1, $2, $3, $4, $5) ORDER BY field(company_id, 83,79,52,44,82) LIMIT $6 [["company_id", 83], ["company_id", 79], ["company_id", 52], ["company_id", 44], ["company_id", 82], ["LIMIT", 11]]
Traceback (most recent call last):
ActiveRecord::StatementInvalid (PG::UndefinedFunction: ERROR: function field(bigint, integer, integer, integer, integer, integer) does not exist)
LINE 1: ...ts"."company_id" IN ($1, $2, $3, $4, $5) ORDER BY field(comp...
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
: SELECT "pages".* FROM "pages" WHERE "pages"."company_id" IN ($1, $2, $3, $4, $5) ORDER BY field(company_id, 83,79,52,44,82) LIMIT $6
I just simply want to call Pages.where(company_id: company_ids) and get the pages back based on order of company_ids that was provided.
As a workaround, I am using this:
company_ids = companies.order("full_name ASC").pluck(:id)
pages = []
company_ids.each {|c| pages << Page.find_by(company_id: c)}
but seems like that would be inefficient if there are thousands of records. or even just hundreds.
The problem is you're using a MySQL function (field), but the RDBMS you're using is PostgreSQL.
You can try with position, using the row company_id and the array of ids concatenated:
Page.where(company_id: company_ids).order("position(company_id::text in '#{ids.join(',')}')")
Use:
Page.where(company_id: company_ids).order(Arel.sql("position(company_id::text in '#{ids.join(',')}')"))
if you're getting a deprecation warning.
There also exists the possibility to use find, which as stated in the doc says The returned records are in the same order as the ids you provide. Although I don't know if it applies for your case.

direct upload to s3 fails with Rails 5.2 ActiveStorage

When I use local as storage service, a blob will be created like:
ActiveStorage::Blob Create (0.3ms) INSERT INTO "active_storage_blobs" ("key", "filename", "content_type", "metadata", "byte_size", "checksum", "created_at") VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING "id" [["key", "9GRt2oNEvae3MV6gNxzLBfzY"], ["filename", "22.jpg"], ["content_type", "image/jpeg"], ["metadata", "{\"identified\":true}"], ["byte_size", 38908], ["checksum", "HWkFPEByP/zWdy1nDW6FHg=="], ["created_at", "2018-07-09 07:53:34.790031"]]
notice the checksum in it is HWkFPEByP/zWdy1nDW6FHg==, while I switched the storage service from local to amazon, the file upload to s3 failed, and the error says:
<?xml version="1.0" encoding="UTF-8"?>
<Error><Code>BadDigest</Code><Message>The Content-MD5 you specified did not match what we received.</Message><ExpectedDigest>1d0c39a9937ce0bec2952fe2be1c4f51</ExpectedDigest><CalculatedDigest>iSb43Wodm0WQp/hAZpKKOg==</CalculatedDigest><RequestId>9018707DCFFCA829</RequestId><HostId>Nop+tXGRYKJlhIy7LU+d4nYtba9i1n3BYnNM+Il60WlH0ZhR53SyHCS2Nox+KVgie9XTIlTOGTg=</HostId></Error>
notice the calculated digest is iSb43Wodm0WQp/hAZpKKOg==, I am not sure which is wrong, Rails or Amazon, please find the picture I am trying to upload here

Timezone issue in Rails

I've never had this before, but somehow when I'm combining a date and a time to a concatenated datetime and store it in the db, I'm off by 2 hours. I just noticed when I started using time_ago_in_words, it's always two hours from now when I just saved something new.
Any idea how to overcome this differnece. I think this is the code that's responsible for the difference:
def create_timestamp
self.date = day.to_datetime + time.seconds_since_midnight.seconds
end
In case anyone is wondering, I'm using a seperate date & time picker on my form, so this the before_save method to create one timestamp for the user input.
Upon request, the SQL for an INSERT at 10:47 CEST, Rails app is in UTC btw:
INSERT INTO "reports" ("account_id", "description", "report_category_id", "day", "time", "user_id", "date", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) RETURNING "id" [["account_id", 2], ["description", ""], ["report_category_id", 4], ["day", "2016-07-30"], ["time", "2000-01-01 10:47:00.000000"], ["user_id", 1], ["date", "2016-07-30 10:47:00.000000"], ["created_at", "2016-07-30 08:47:53.828175"], ["updated_at", "2016-07-30 08:47:53.828175"]]

rspec model test failing

I am writing an app to help me keep track of my social media advertising budgets. When you enter a new advert it should calculate and update the amount spent on the budget it is drawing from. Here is my model that achieves that.
class Advert < ActiveRecord::Base
belongs_to :budget
before_save :update_budget
after_destroy :update_budget
validates :budget_id, :name, :platform, :ad_type, :amount, :start_date, :end_date, presence: true
validates :amount, numericality: true
validate :check_budget
# Checks to see if there is enough budget remaining to set up advert
def check_budget
if self.amount > self.budget.amount_remaining
errors.add(:amount, " cannot exceed amount remaining in budget.")
end
end
# Updates the amount remaining in the budget on advert save.
def update_budget
budget = Budget.find(self.budget_id)
#adverts = Advert.all
total_spent = self.amount
#adverts.each do |advert|
if advert.budget_id == self.budget_id
total_spent += advert.amount
end
end
budget.amount_spent = total_spent
budget.save
end
end
This all works but I am currently teaching myself to write tests so I thought I would write a test in rspec for it.
require 'rails_helper'
describe Advert do
it "updates budget before save" do
advert = create(:advert)
budget = advert.budget
expect(budget.amount_spent).to eq(advert.amount)
expect(budget.amount_remaining).to eq(budget.amount - budget.amount_spent)
end
end
However, this test if failing but I cannot figure out why. Here is the error code.
1) Advert updates budget before save
Failure/Error: expect(budget.amount_spent).to eq(advert.amount)
expected: 7.0 (#<BigDecimal:7ffa61358b18,'0.7E1',9(18)>)
got: 0.0 (#<BigDecimal:7ffa6026a9a0,'0.0',9(18)>)
(compared using ==)
# ./spec/models/advert_spec.rb:27:in `block (2 levels) in <top (required)>'
And here is the relevant test log.
SQL (0.3ms) INSERT INTO "budgets" ("name", "amount", "client_id", "amount_remaining", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5, $6) RETURNING "id" [["name", "eos"], ["amount", "432.0"], ["client_id", 102], ["amount_remaining", "432.0"], ["created_at", "2016-03-12 18:08:54.607999"], ["updated_at", "2016-03-12 18:08:54.607999"]]
(0.1ms) RELEASE SAVEPOINT active_record_1
(0.2ms) SAVEPOINT active_record_1
Budget Load (0.4ms) SELECT "budgets".* FROM "budgets" WHERE "budgets"."id" = $1 LIMIT 1 [["id", 49]]
Advert Load (0.5ms) SELECT "adverts".* FROM "adverts"
SQL (0.4ms) UPDATE "budgets" SET "amount_spent" = $1, "amount_remaining" = $2, "updated_at" = $3 WHERE "budgets"."id" = $4 [["amount_spent", "7.0"], ["amount_remaining", "425.0"], ["updated_at", "2016-03-12 18:08:54.616491"], ["id", 49]]
SQL (0.4ms) INSERT INTO "adverts" ("budget_id", "name", "platform", "ad_type", "amount", "start_date", "end_date", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) RETURNING "id" [["budget_id", 49], ["name", "ut"], ["platform", "voluptate"], ["ad_type", "facere"], ["amount", "7.0"], ["start_date", "2016-03-01"], ["end_date", "2016-04-12"], ["created_at", "2016-03-12 18:08:54.619698"], ["updated_at", "2016-03-12 18:08:54.619698"]]
(0.2ms) RELEASE SAVEPOINT active_record_1
(0.2ms) ROLLBACK
Interestingly if I comment out the first 'expect' the test passes. It's as though it cannot access advert.amount so set's it as 0.
Anyone have any ideas?
This solved my issue.
describe Advert do
it "updates budget before save" do
advert = build(:advert)
budget = advert.budget
expect(budget.amount_spent).to eq(0)
advert.save
budget.reload
expect(budget.amount_spent).to eq(advert.amount)
expect(budget.amount_remaining).to eq(budget.amount - budget.amount_spent)
end
I think the source of my problem was not reloading my budget which meant that I was trying to access the attribute before it had been updated.

creation of a nested_attributes makes before_create not work

I'm tried to create a User in the console doing:
2.2.1 :012 > u.save!
(0.2ms) BEGIN
User Exists (0.7ms) SELECT 1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER('noc#co.co') LIMIT 1
SQL (2.1ms) INSERT INTO "users" ("id", "first_name", "last_name", "email", "title", "time_zone", "company_id", "password_digest", "created_at", "updated_at", "activation_digest") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11) RETURNING "id" [["id", 200], ["first_name", "Random"], ["last_name", "Dude"], ["email", "noc#co.co"], ["title", "CEO"], ["time_zone", "Stockholm"], ["company_id", 1], ["password_digest", "$2a$10$bHHA/JP5IMrucGUXRWMpsO8sInaouSqn48M.fDHpjGdvedu3Napra"], ["created_at", "2015-10-11 23:09:38.213109"], ["updated_at", "2015-10-11 23:09:38.213109"], ["activation_digest", "$2a$10$WF3bUOtbC1gk4ZnX58cJZO5k7P7YV6wvhmwz7EErTdvIseNuy0oyq"]]
2.2.1 :013 > u.activation_token
=> "vKrs0jtvZRiyU-YVE-aPXw"
now when I try to create a user the before_create doesn't work, I tried changing it to before_validation and that didn't work either.
The user is a nested attribute from companies, and is created in Companies#new.
class User < ActiveRecord::Base
belongs_to :company
attr_accessor :remember_token, :activation_token, :reset_token
before_save :downcase_email
before_create :create_activation_digest
now when I do #user.activation_token it returns nil. Here's the console log from when I try it on the app:
Started POST "/companies" for ::1 at 2015-10-12 01:31:47 +0200
Processing by CompaniesController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"ZTEtGR2Dd1FDDYm9j4/SiqSTP646R8gctFx4aJHM9QDP+RQky8SG6gkomLbf+E+LgMi+aah1YOhCkUsg3uSYoQ==", "company"=>{"time_zone"=>"Stockholm", "users_attributes"=>{"0"=>{"first_name"=>"swaga", "last_name"=>"swaga", "email"=>"swaga#wkoa.com", "password"=>"[FILTERED]"}}, "name"=>"swaga"}, "commit"=>"Create Company"}
(0.2ms) BEGIN
User Exists (1.3ms) SELECT 1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER('swaga#wkoa.com') LIMIT 1
SQL (7.1ms) INSERT INTO "companies" ("name", "time_zone", "created_at", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id" [["name", "swaga"], ["time_zone", "Stockholm"], ["created_at", "2015-10-11 23:31:47.380530"], ["updated_at", "2015-10-11 23:31:47.380530"]]
SQL (0.5ms) INSERT INTO "users" ("first_name", "last_name", "email", "password_digest", "activation_digest", "company_id", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5, $6, $7, $8) RETURNING "id" [["first_name", "swaga"], ["last_name", "swaga"], ["email", "swaga#wkoa.com"], ["password_digest", "$2a$10$3GsPACTg5HPodiqdedsCvu52N64BEE3/fA77p.oBHAhM51zCSzUV."], ["activation_digest", "$2a$10$75y9jP.eZxmWI1KjHZrg3.DuB5GSwiS2UsaQdtV25ClBHDi.z4Pte"], ["company_id", 8], ["created_at", "2015-10-11 23:31:47.390462"], ["updated_at", "2015-10-11 23:31:47.390462"]]
(6.7ms) COMMIT
User Load (0.9ms) SELECT "users".* FROM "users" WHERE "users"."company_id" = $1 ORDER BY "users"."id" ASC LIMIT 1 [["company_id", 8]]
Rendered user_mailer/account_activation.html.erb within layouts/mailer (7.8ms)
UserMailer#account_activation: processed outbound mail in 29.2ms
Completed 500 Internal Server Error in 380ms (ActiveRecord: 16.9ms)
ActionController::UrlGenerationError - No route matches {:action=>"edit", :controller=>"account_activations", :email=>"swaga#wkoa.com", :id=>nil} missing required keys: [:id]:
now I see that the activation_digest is returned, so I think the issue is literarily just the before_create not working? Which is weird because then it shouldn't be able to create an activation digest as the two are connected:
# Creates and assigns the activation token and digest.
def create_activation_digest
self.activation_token = User.new_token
self.activation_digest = User.digest(activation_token)
end
Your error says:
ActionController::UrlGenerationError - No route matches {:action=>"edit", :controller=>"account_activations", :email=>"swaga#wkoa.com", :id=>nil} missing required keys: [:id]:
Seems like, in your view, you are calling edit_account_activation_path without the id param and that's creating the problem for you. Try to send the user.id as a parameter in the edit_account_activation_path call.
Something like this:
edit_account_activation_path(user.email, user.id)
That should fix your issue.

Resources