Rails 7 `turbo_stream_from` not updating view - ruby-on-rails

Running Rails 7.0.4 and trying to get a basic turbo_stream_from implemented. According to logs, it's broadcasting/transmitting appropriately, but the view itself is not updating.
My issue appears to be identical to this question, but the solution with Redis not being running/installed is not my issue (Redis is properly installed and running).
Have restarted the app, console and redis a dozen times.
# show.html.erb
<%= turbo_stream_from "documents" %>
# document.rb
class Document < ApplicationRecord
after_update_commit -> { broadcast_update_to "documents", partial: "documents/summary", locals: { document: self }, target: "document_#{self.id}" }
end
# documents/_summary.html.erb
<p class="mb-3 text-sm text-slate-500"><%= pluralize(time_to_read(document.summary), "minute") %> • <%= word_count(document.summary) %> words</p>
<%= markdown document.summary %>
irb(main):004:0> document.touch
TRANSACTION (0.6ms) BEGIN
Document Update (1.9ms) UPDATE "documents" SET "updated_at" = $1 WHERE "documents"."id" = $2 [["updated_at", "2023-01-07 18:24:21.823597"], ["id", "05feddd8-2fb7-4432-9eda-7db07616d613"]]
TRANSACTION (0.3ms) COMMIT
Rendered documents/_summary.html.erb (Duration: 0.6ms | Allocations: 96)
[ActionCable] Broadcasting to documents: "<turbo-stream action=\"append\" target=\"document_05feddd8-2fb7-4432-9eda-7db07616d613\"><template><p class=\"mb-3 text-sm text-slate-500\">1 minute • 38 words</p>\n<p>-The study of a 2,000-year-old city wall made of concrete reveals the sustainability of the Roman's use of quicklime i...
=> true
12:24:55 web.1 | Started GET "/cable" [WebSocket] for ::1 at 2023-01-07 12:24:55 -0600
12:24:55 web.1 | Successfully upgraded to WebSocket (REQUEST_METHOD: GET, HTTP_CONNECTION: Upgrade, HTTP_UPGRADE: websocket)
12:24:55 web.1 | Turbo::StreamsChannel is transmitting the subscription confirmation
12:24:55 web.1 | Turbo::StreamsChannel is streaming from documents
12:25:17 web.1 | Turbo::StreamsChannel transmitting "<turbo-stream action=\"append\" target=\"document_05feddd8-2fb7-4432-9eda-7db07616d613\"><template><p class=\"mb-3 text-sm text-slate-500\">1 minute • 38 words</p>\n<p>-The study of a 2,000-year-old city wall made of concrete reveals the sustainability of the Roman's use of quicklime in... (via streamed from documents)
This is what I see on the rendered page:
<turbo-cable-stream-source channel="Turbo::StreamsChannel" signed-stream-name="ImRvY3VtZW50cyI=--a3f0177252c55b1545ca8ef5c030cc9ed23496182d09168cd9ef3441d9510d22"></turbo-cable-stream-source>

Related

How to make RSpec & Capybara wait long enough for ActionCable to complete?

Rails 6 with ActionCable
Rspec 3.10
Capybara 3.36
Users visit edit_inventory_path #inventory and see a collection of Counts.
Clicking on a count triggers an AJAX call to populate a modal with the count _form
Filling out the form and clicking submit triggers:
CountsChannel.broadcast_to(
#inventory,
{
count_id: #count.id,
html_slug: render_to_string(partial: 'counts/count', collection: #inventory.counts.sort_by { |c| [c.sort_by_status, - c.item.name] }),
uncounted: "#{view_context.pluralize(#inventory.counts.uncounted.size, 'item')} uncounted."
}
)
This replaces every count div on the page. The newly submitted count is sorted to the bottom of the page and the button text changes.
My test is expecting that button to change from "Count" to "Edit".
RSpec.describe 'Performing an inventory', type: :system do
...
context 'when submitting a count' do
...
it 'changes the count button text' do
# making sure page is loaded
expect(page).to have_content "Edit #{inventory.name}"
# clicking the button opens a modal.
# AJAX puts the count edit form in the modal before it open
find("div#count_#{Count.first.id} a.count-btn").click
# wait to make sure the modal is open
find('input#count_unopened_boxes_count')
fill_in 'count_unopened_boxes_count', with: 5
click_button('Submit')
Rails.logger.debug 'HEYA just hit the submit button.'
# clicking the button closes and clears the modal
# and AJAXs form data to CountsController#update
# which triggers the ActionCable broadcast
# HERE: find('the button', wait: 5) does nothing
# because the old div is still on the page
# so Capybara finds it right away
# wait is a maximum wait time, not an absolute
count_1_btn_text = find("div#count_#{Count.first.id} a.count-btn").text
Rails.logger.debug 'HEYA found the button.'
Rails.logger.debug 'HEYA hoping ActionCable is complete.'
expect(count_1_btn_text).to eq 'Loose Count'
# some time later, the button text actually changes
end
end
end
I know it's a timing issue when I check out test.log:
...
Started GET "/inventories/1/edit" for 127.0.0.1 at 2021-11-29 12:51:05 -0500
...
Processing by InventoriesController#edit as HTML
Parameters: {"id"=>"1"}
...
Rendering layout layouts/application.haml
Rendering inventories/edit.haml within layouts/application
...
Rendered collection of counts/_count.haml [11 times] (Duration: 53.0ms | Allocations: 26025)
...
Completed 200 OK in 10635ms (Views: 10574.2ms | ActiveRecord: 15.7ms | Allocations: 645565)
...
Started GET "/assets/channels/consumer-ddc23d99c3f3572746769fa1851baebf4ef5d005651f6ac89f0739c1682a80bc.js" for 127.0.0.1 at 2021-11-29 12:51:15 -0500
Started GET "/assets/channels/counts_channel-6e2c07931c38a8f979370ee55ad4ca4783da4a2def12996ad4efe6f213d4fb78.js" for 127.0.0.1 at 2021-11-29 12:51:16 -0500
Started GET "/cable" for 127.0.0.1 at 2021-11-29 12:51:16 -0500
Started GET "/cable/" [WebSocket] for 127.0.0.1 at 2021-11-29 12:51:16 -0500
Successfully upgraded to WebSocket (REQUEST_METHOD: GET, HTTP_CONNECTION: Upgrade, HTTP_UPGRADE: websocket)
[1m[36mUser Load (0.6ms)[0m [1m[34mSELECT "users".* FROM "users" WHERE "users"."id" = 1 ORDER BY "users"."id" ASC LIMIT 1[0m
Registered connection (Z2lkOi8vYnVpbGQtcGxhbm5lci9Vc2VyLzE)
...
[1m[36mInventory Load (44.2ms)[0m [1m[34mSELECT "inventories".* FROM "inventories" WHERE "inventories"."id" = 1 LIMIT 1[0m
CountsChannel is transmitting the subscription confirmation
CountsChannel is streaming from counts:Z2lkOi8vYnVpbGQtcGxhbm5lci9JbnZlbnRvcnkvMQ
...
...
Rendered counts/_edit.haml (Duration: 48.7ms | Allocations: 28122)
Rendered counts/edit.js.erb (Duration: 50.3ms | Allocations: 28697)
Completed 200 OK in 66ms (Views: 56.2ms | ActiveRecord: 3.4ms | Allocations: 34258)
HEYA just hit the submit button.
...
Started PATCH "/inventories/1/counts/1" for 127.0.0.1 at 2021-11-29 12:51:17 -0500
Processing by CountsController#update as JS
Parameters: {"count"=>{"loose_count"=>"0", "unopened_boxes_count"=>"5"}, "partial_box"=>"Submit Box Count", "inventory_id"=>"1", "id"=>"1"}
HEYA found the button.
HEYA hoping ActionCable is complete.
... 49 lines later ...
[ActionCable] Broadcasting to counts:Z2lkOi8vYnVpbGQtcGxhbm5lci9JbnZlbnRvcnkvMQ: {:count_id=>1, :html_slug=>"...real long string...", :uncounted=>"11 items uncounted."}
Rendering counts/update.js.erb
CountsChannel transmitting {"count_id"=>1, "html_slug"=>"...really long string... (via streamed from counts:Z2lkOi8vYnVpbGQtcGxhbm5lci9JbnZlbnRvcnkvMQ)
Rendered counts/update.js.erb (Duration: 41.1ms | Allocations: 674)
Completed 200 OK in 344ms (Views: 56.4ms | ActiveRecord: 123.9ms | Allocations: 30670)
Finished "/cable/" [WebSocket] for 127.0.0.1 at 2021-11-29 12:51:18 -0500
CountsChannel stopped streaming from counts:Z2lkOi8vYnVpbGQtcGxhbm5lci9JbnZlbnRvcnkvMQ
I've been taught that doing things like sleep() are bad practices, so what are my options to force Capybara to wait a few seconds?
Just tell Capybara what you expect it to find on the page and maximum time to wait for that to appear. In your question you say that you're expecting the button to change from "Count" to "Edit" but then your code is checking for "Loose Count" so I'm not fully clear on exactly what visible change you're expecting, but assuming the latter you could just do something like
expect(page).to have_css("div#count_#{Count.first.id} a.count-btn", text: 'Loose Count', wait: 10)
Additionally there's no point in doing a find followed by fill_in just to wait for the element to appear because fill_in will already wait for the element to appear, so
find('input#count_unopened_boxes_count')
fill_in 'count_unopened_boxes_count', with: 5
is effectively the same as just doing
fill_in 'count_unopened_boxes_count', with: 5

link_to delete method takes me to 'show' page on rails

I'm new to Rails and can't seem to figure this out
Every time I click the link it doesn't delete the article, it just takes me to the show view. Not sure why this is happening. Here is my code for the link:
<%= link_to 'delete', article_path(article.id), method: :delete, data: { confirm: "Are you sure?" } %>
my rails server shows a GET request even though I specified the method (I think):
Started GET "/articles/1" for ::1 at 2020-09-07 10:05:13 -0700
Processing by ArticlesController#show as HTML
Parameters: {"id"=>"1"}
Article Load (0.7ms) SELECT "articles".* FROM "articles" WHERE "articles"."id" = ? LIMIT ?
[["id", 1], ["LIMIT", 1]]
↳ app/controllers/articles_controller.rb:46:in `set_article'
Rendering articles/show.html.erb within layouts/application
Rendered articles/show.html.erb within layouts/application (Duration: 4.0ms | Allocations: 321)
[Webpacker] Everything's up-to-date. Nothing to do
Rendered layouts/_flashMessages.erb (Duration: 0.2ms | Allocations: 18)
Rendered layouts/_navBar.html.erb (Duration: 0.1ms | Allocations: 5)
Completed 200 OK in 123ms (Views: 96.9ms | ActiveRecord: 0.7ms | Allocations: 5344)
I can't figure out why. Any help is appreciated. Thanks!
I had the same issue in Rails 6. It seems that a wrong version of jquery can cause this. Somehow #rails/ujs stopps working correctly if you install the wrong jquery version.
If you have no errors in your code you can try to fix it by deleting the jquery gem and add jquery through yarn (my question concering this topic)

Upload text file without a dedicated model using active storage

I have a Task resource containing many tasks. I want to upload a text file containing multiple tasks and import them into the Task model.
I haven't used active storage (AS) before, so I have been combing through the docs. I get that the standard way of using AS is to have a model of records where each record has a file attached. I my case that would mean that I could create an importer model and the have one record for each import action. I feel that that is the wrong approach - I would much rather have an action on the task controller called import that can handle an uploaded file and the import all entries from the file into the task model.
I am trying to make this work with Direct Uploads I have created a form for this:
<%= form_with(model: #task, action: 'start_upload', local: true) do |form| %>
<%= form.file_field :attachments, multiple: false, direct_upload: true %>
<div class="form-group col-sm-6">
<%= form.submit "Save", :class => "btn btn-primary" %>
</div>
<% end %>
This works in some way; the file is uploaded - I see it in a folder (/Users/mhe/Documents/projects/mags/storage/3c/jf/3cjfvr062yd3y6wx8lly4llpdn9x). But I have no way of getting to the file.
The output to the log is:
Started POST "/rails/active_storage/direct_uploads" for ::1 at 2020-04-15 22:18:04 +0200
Processing by ActiveStorage::DirectUploadsController#create as JSON
Parameters: {"blob"=>{"filename"=>"movielist.txt", "content_type"=>"text/plain", "byte_size"=>23610, "checksum"=>"EEzCXGDVCwhcAzfHLvERaw=="}, "direct_upload"=>{"blob"=>{"filename"=>"movielist.txt", "content_type"=>"text/plain", "byte_size"=>23610, "checksum"=>"EEzCXGDVCwhcAzfHLvERaw=="}}}
(0.1ms) begin transaction
ActiveStorage::Blob Create (0.4ms) INSERT INTO "active_storage_blobs" ("key", "filename", "content_type", "byte_size", "checksum", "created_at") VALUES (?, ?, ?, ?, ?, ?) [["key", "ge8ztddg14tapio9cw0x7lf5lu79"], ["filename", "movielist.txt"], ["content_type", "text/plain"], ["byte_size", 23610], ["checksum", "EEzCXGDVCwhcAzfHLvERaw=="], ["created_at", "2020-04-15 20:18:04.108179"]]
(0.8ms) commit transaction
Disk Storage (0.3ms) Generated URL for file at key: ge8ztddg14tapio9cw0x7lf5lu79 (http://localhost:3000/rails/active_storage/disk/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdDVG9JYTJWNVNTSWhaMlU0ZW5Sa1pHY3hOSFJoY0dsdk9XTjNNSGczYkdZMWJIVTNPUVk2QmtWVU9oRmpiMjUwWlc1MFgzUjVjR1ZKSWc5MFpYaDBMM0JzWVdsdUJqc0dWRG9UWTI5dWRHVnVkRjlzWlc1bmRHaHBBanBjT2cxamFHVmphM04xYlVraUhVVkZla05ZUjBSV1EzZG9ZMEY2WmtoTWRrVlNZWGM5UFFZN0JsUT0iLCJleHAiOiIyMDIwLTA0LTE1VDIwOjIzOjA0LjExM1oiLCJwdXIiOiJibG9iX3Rva2VuIn19--f5314cff4278fed290a6ac3c1ee54c31542e9984)
Completed 200 OK in 19ms (Views: 0.3ms | ActiveRecord: 1.8ms | Allocations: 12779)
Started PUT "/rails/active_storage/disk/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdDVG9JYTJWNVNTSWhaMlU0ZW5Sa1pHY3hOSFJoY0dsdk9XTjNNSGczYkdZMWJIVTNPUVk2QmtWVU9oRmpiMjUwWlc1MFgzUjVjR1ZKSWc5MFpYaDBMM0JzWVdsdUJqc0dWRG9UWTI5dWRHVnVkRjlzWlc1bmRHaHBBanBjT2cxamFHVmphM04xYlVraUhVVkZla05ZUjBSV1EzZG9ZMEY2WmtoTWRrVlNZWGM5UFFZN0JsUT0iLCJleHAiOiIyMDIwLTA0LTE1VDIwOjIzOjA0LjExM1oiLCJwdXIiOiJibG9iX3Rva2VuIn19--f5314cff4278fed290a6ac3c1ee54c31542e9984" for ::1 at 2020-04-15 22:18:04 +0200
Processing by ActiveStorage::DiskController#update as */*
Parameters: {"encoded_token"=>"eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdDVG9JYTJWNVNTSWhaMlU0ZW5Sa1pHY3hOSFJoY0dsdk9XTjNNSGczYkdZMWJIVTNPUVk2QmtWVU9oRmpiMjUwWlc1MFgzUjVjR1ZKSWc5MFpYaDBMM0JzWVdsdUJqc0dWRG9UWTI5dWRHVnVkRjlzWlc1bmRHaHBBanBjT2cxamFHVmphM04xYlVraUhVVkZla05ZUjBSV1EzZG9ZMEY2WmtoTWRrVlNZWGM5UFFZN0JsUT0iLCJleHAiOiIyMDIwLTA0LTE1VDIwOjIzOjA0LjExM1oiLCJwdXIiOiJibG9iX3Rva2VuIn19--f5314cff4278fed290a6ac3c1ee54c31542e9984"}
Disk Storage (4.7ms) Uploaded file to key: ge8ztddg14tapio9cw0x7lf5lu79 (checksum: EEzCXGDVCwhcAzfHLvERaw==)
No template found for ActiveStorage::DiskController#update, rendering head :no_content
Completed 204 No Content in 6ms (ActiveRecord: 0.0ms | Allocations: 5806)
Started POST "/tasks/upload" for ::1 at 2020-04-15 22:18:04 +0200
Processing by TasksController#do_upload as HTML
Parameters: {"authenticity_token"=>"wufWKGXHYX/obGYtKkL8SVSy5uSd/Z2XFLDxvLkDKdGQicsUPjEks9riYloTzorjhX8PgFUIj/BXV4VFi1ihKQ==", "attachments"=>"eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBEZz09IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--c47b93b4598d01bf7f9b47caa0660fd39ab9b8df", "commit"=>"Save"}
Completed 500 Internal Server Error in 2ms (ActiveRecord: 0.0ms | Allocations: 1300)
And thus the params I get from the upload form are simply:
{"authenticity_token"=>"wufWKGXHYX/obGYtKkL8SVSy5uSd/Z2XFLDxvLkDKdGQicsUPjEks9riYloTzorjhX8PgFUIj/BXV4VFi1ihKQ==", "attachments"=>"eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBEZz09IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--c47b93b4598d01bf7f9b47caa0660fd39ab9b8df", "commit"=>"Save", "controller"=>"tasks", "action"=>"do_upload"}
I read about how I should be able to do something like this:
blob = ActiveStorage::Blob.create_after_upload!(
io: params[:file],
filename: params[:file].original_filename,
content_type: params[:file].content_type
)
render json: { filelink: url_for(blob) }
or
ActiveStorage::Blob.service.path_for(params['key'])
But I don't have file nor key in the params - I see them output to the log, though.
So I'm looking for some guidance on how to achieve the usecase... thanks

Back Button Skipping Page in Ruby on Rails application

I have found many generic posts suggesting this has to do with redirects. I believe this may be due to how I have a form set up.
On the plans.html.erb page I have a form with four submits, each going to the same place with different params:
<%= form_with url: :affiliate_select_plan, class: "mx-auto" do |f| %>
<!-- Paid Plans -->
<% #plans.each_with_index do |plan, i| %>
<%= f.button 'Select Plan', value: plan[:name], type: 'submit' %>
<% end %>
<% end %>
I have the affiliate_select_plan_path setup in my routes.rb:
devise_scope :affiliate do
post 'affiliate/select_plan', :to => 'affiliates/registrations#select_plan'
end
The form successfully hits the select_plan method in the controller, which redirects it to the new_affiliate_registration_path, passing the needed params.
def select_plan
redirect_to new_affiliate_registration_path(plan: plan_params[:button])
end
The new method in the controller is called, directing the user to the sign up page:
# GET /resource/sign_up
def new
#plan = AffiliatePlan.find_by(nickname: params.permit(:plan)[:plan].downcase)
super
end
From this page, if the back button on the browser is selected, it will bring the user back to the page they were at before being at plans.html.erb.
Could this be related to the redirect_to?
EDIT:
Here are the logs:
Started GET "/" for 127.0.0.1 at 2020-02-25 19:06:02 -0500
Processing by Affiliates::RegistrationsController#plans as HTML
Rendering affiliates/registrations/plans.html.erb within layouts/application
Rendered affiliates/registrations/plans.html.erb within layouts/application (5.2ms)
Rendered layouts/_google_analytics.html.erb (0.5ms)
[Webpacker] Everything's up-to-date. Nothing to do
Rendered layouts/_header.html.erb (1.2ms)
Rendered layouts/_footer.html.erb (0.7ms)
Completed 200 OK in 195ms (Views: 194.2ms | ActiveRecord: 0.0ms)
Started POST "/partner/select_plan" for 127.0.0.1 at 2020-02-25 19:06:13 -0500
Processing by Affiliates::RegistrationsController#select_plan as JS
Parameters: {"utf8"=>"✓", "authenticity_token"=>"Ck8HGRryriXleQrUjCSKjTrIRLIw273EdSu4WZnFn3kAL1mMmk7jqR1tZgnPniHsMzHFMl81vPBRuvA0/W4uSw==", "button"=>"Local"}
Unpermitted parameters: :utf8, :authenticity_token
Redirected to http://localhost:3000/partners/sign_up?plan=Local
Completed 200 OK in 1ms (ActiveRecord: 0.0ms)
Started GET "/partners/sign_up?plan=Local" for 127.0.0.1 at 2020-02-25 19:06:13 -0500
Processing by Affiliates::RegistrationsController#new as HTML
Parameters: {"plan"=>"Local"}
AffiliatePlan Load (1.2ms) SELECT "affiliate_plans".* FROM "affiliate_plans" WHERE "affiliate_plans"."nickname" = $1 LIMIT $2 [["nickname", "local"], ["LIMIT", 1]]
↳ app/controllers/affiliates/registrations_controller.rb:11
Rendering affiliates/registrations/new.html.erb within layouts/application
Rendered affiliates/registrations/new.html.erb within layouts/application (4.6ms)
Rendered layouts/_google_analytics.html.erb (1.1ms)
[Webpacker] Everything's up-to-date. Nothing to do
Rendered layouts/_header.html.erb (1.2ms)
Rendered layouts/_footer.html.erb (0.7ms)
Completed 200 OK in 191ms (Views: 187.6ms | ActiveRecord: 1.2ms)
I have a hunch that this might have to do with form resubmission: Forms and the back button tend to be a bit wonky at times.
However, instead of going more in depth with this, let me point you in another direction. I'm doing this because to me, this looks like a classic case of someone trying to find a solution to the wrong problem. I'm saying this because based on the code and log snippets you've provided, you're jumping through hoops to pass a parameter (in your case the name of a plan) via multiple actions – which, if I'm right, is just unnecessary.
Here's what I would do instead:
<% #plans.each do |plan| %>
<%=
link_to 'Select Plan',
new_affiliate_registration_path(plan: plan.downcase),
class: 'some-button-class
%>
<% end %>
This way, you don't have to mess around in your controllers in any way. Also, since there is no POST request, you won't have any issues with form (re)population and such things.

Dalli/Memcached looks like caching but it's not caching in development environment

Rails 4.0.4
Unicorn
Dalli 2.7
Memcached 1.4.17
development.rb is set up to use caching in dev env:
config.cache_classes = true
config.action_controller.perform_caching = true
config.cache_store = :dalli_store
Weird thing is at the logs, see it:
18:57:15 web.1 | Program Load (3.1ms) SELECT "programs".* FROM "programs" WHERE "programs"."is_deleted" = 'f' AND (poster_file_name IS NOT NULL) AND ("programs"."poster_file_name" != 'yumurcatvkucuk.jpg') LIMIT 10
18:57:15 web.1 | Cache read: views/programs/21-20140408150833637850000/programs/807-20140408150843947601000/programs/925-20140408150845273240000/programs/872-20140418084359291046000/programs/132-20140408150835259856000/programs/136-20140408150835308846000/programs/140-20140408150835371772000/programs/1280-20140408150849908310000/programs/340-20140408150837584935000/programs/150-20140408150835553155000/adc205508053828cb96d93c37b9ad0f7
18:57:15 web.1 | Read fragment views/programs/21-20140408150833637850000/programs/807-20140408150843947601000/programs/925-20140408150845273240000/programs/872-20140418084359291046000/programs/132-20140408150835259856000/programs/136-20140408150835308846000/programs/140-20140408150835371772000/programs/1280-20140408150849908310000/programs/340-20140408150837584935000/programs/150-20140408150835553155000/adc205508053828cb96d93c37b9ad0f7 (0.6ms)
18:57:15 web.1 | Rendered pages/index.html.erb within layouts/application (47.8ms)
18:57:15 web.1 | Program Load (2.8ms) SELECT "programs".* FROM "programs" WHERE "programs"."is_deleted" = 'f' AND "programs"."category_id" = 10 ORDER BY "programs"."order_no" ASC LIMIT 14
18:57:15 web.1 | Category Load (2.4ms) SELECT "categories".* FROM "categories" WHERE "categories"."id" IN (10)
18:57:15 web.1 | Cache read: views/programs/8-20140408150833498130000/programs/19-20140408150833622733000/programs/30-20140408150833742922000/programs/24-20140408150833663802000/programs/1021-20140408150846580202000/programs/872-20140418084359291046000/programs/1187-20140408150848167962000/programs/866-20140408150844626941000/programs/1280-20140408150849908310000/programs/881-20140408150844749467000/programs/1376-20140408150850766221000/programs/1379-20140408150850809312000/programs/1437-20140408150851047434000/programs/3-20140408150832973507000/6c2638ad89493f0c3e448b3d66c4a1de
18:57:15 web.1 | Read fragment views/programs/8-20140408150833498130000/programs/19-20140408150833622733000/programs/30-20140408150833742922000/programs/24-20140408150833663802000/programs/1021-20140408150846580202000/programs/872-20140418084359291046000/programs/1187-20140408150848167962000/programs/866-20140408150844626941000/programs/1280-20140408150849908310000/programs/881-20140408150844749467000/programs/1376-20140408150850766221000/programs/1379-20140408150850809312000/programs/1437-20140408150851047434000/programs/3-20140408150832973507000/6c2638ad89493f0c3e448b3d66c4a1de (0.7ms)
18:57:15 web.1 | Episode Load (2.8ms) SELECT "episodes".* FROM "episodes" WHERE "episodes"."is_deleted" = 'f' AND "episodes"."episode_type_id" = 2 ORDER BY "episodes"."id" DESC LIMIT 7
18:57:15 web.1 | Program Load (2.6ms) SELECT "programs".* FROM "programs" WHERE "programs"."is_deleted" = 'f' AND "programs"."id" IN (1340, 711, 5, 1380, 1344, 1311, 1210)
18:57:15 web.1 | Cache read: views/episodes/149768-20140419064643365309000/episodes/149752-20140419064643075387000/episodes/149748-20140419064642994891000/episodes/149740-20140419064642741006000/episodes/149738-20140419064642706457000/episodes/149736-20140419064642673073000/episodes/149726-20140419064642492558000/6c2638ad89493f0c3e448b3d66c4a1de
18:57:15 web.1 | Read fragment views/episodes/149768-20140419064643365309000/episodes/149752-20140419064643075387000/episodes/149748-20140419064642994891000/episodes/149740-20140419064642741006000/episodes/149738-20140419064642706457000/episodes/149736-20140419064642673073000/episodes/149726-20140419064642492558000/6c2638ad89493f0c3e448b3d66c4a1de (0.6ms)
18:57:15 web.1 | Episode Load (3.5ms) SELECT "episodes".* FROM "episodes" WHERE "episodes"."is_deleted" = 'f' AND "episodes"."episode_type_id" = 1 ORDER BY "episodes"."id" DESC LIMIT 12
18:57:15 web.1 | Program Load (2.6ms) SELECT "programs".* FROM "programs" WHERE "programs"."is_deleted" = 'f' AND "programs"."id" IN (1016, 341)
18:57:15 web.1 | Cache read: views/episodes/149773-20140419094829793071000/episodes/149772-20140419091743738305000/episodes/149771-20140419091322119681000/episodes/149770-20140419100721271419000/episodes/149761-20140419064643243075000/episodes/149760-20140419064643225958000/episodes/149759-20140419064643207847000/episodes/149758-20140419064643182828000/episodes/149757-20140419064643166963000/episodes/149756-20140419064643149717000/episodes/149755-20140419064643132085000/episodes/149754-20140419064643113035000/6c2638ad89493f0c3e448b3d66c4a1de
18:57:15 web.1 | Read fragment views/episodes/149773-20140419094829793071000/episodes/149772-20140419091743738305000/episodes/149771-20140419091322119681000/episodes/149770-20140419100721271419000/episodes/149761-20140419064643243075000/episodes/149760-20140419064643225958000/episodes/149759-20140419064643207847000/episodes/149758-20140419064643182828000/episodes/149757-20140419064643166963000/episodes/149756-20140419064643149717000/episodes/149755-20140419064643132085000/episodes/149754-20140419064643113035000/6c2638ad89493f0c3e448b3d66c4a1de (0.6ms)
It writes and reads cache fragments BUT it runs all SQL each time I refresh the page! The logs are always same after all of my refreshes. It was supposed to show only fragment readings after the first loading??
I tried reinstalling Dalli gem, upgraded memcached to latest version.
When I try caching and fetching data in console, it's successful. Caching also works in production.
I'm using mini_profiler to see SQL transactions in dev env and I see the same SQLs in mini_profiler popup too...
Do you have an idea? What's going on?
A part from my view file:
<% cache #latest_episodes do %>
<% #latest_episodes.each do |t| %>
<% cache(t) do %>
<%= render 'common/slider_item', episode: t, lazy_owl: true %>
<% end %>
<% end %>
<% end %>
I'm still not so clear about the issue but I've found the reason.
As I stated in my question, the code I used in my view was like this:
<% cache #latest_episodes do %>
<% #latest_episodes.each do |t| %>
<% cache(t) do %>
<%= render 'common/slider_item', episode: t, lazy_owl: true %>
<% end %>
<% end %>
<% end %>
When I changed the instance variables to regular string keys and removed cache(t) blocks, everything worked just fine.
I guess this issue occurred because Rails had to recreate the cache key on each request by processing the instance variables. But if it's the point, how come does Rails also have an auto-expiring mechanism? The statement I guess shows that it should always hit the database to create cache keys.
Any comment would be appreciated on this.

Resources