Trouble displaying individual images from array (Rails active storage) - ruby-on-rails

I'm sure this should be simple and I'm overlooking something daft.
Rails 6.1.1
Ruby 3.0.0
I'm using active storage to attach multiple 'photos' to my Articles model.
In Articles 'show.html.erb' I want to place the photos in a number of different places in the article, not looping all of them in a row in the same place.
show.html.erb
<% #first2photos.each do |article| %>
<%= image_tag(article.photos) %>
<% end %>
articles.controller.erb
def show
#first2photos = Article.order("created_at DESC").first(2)
end
This gives the following error:
Can't resolve image into URL: undefined method `to_model' for #<ActiveStorage::Attached::Many:0x00007fdbbfa852a8 #name="photos", #record=#<Article id: 1, title: "This is the first post", snippet: "Hopefully this will also attach a couple of photos", body: "Nullam ac odio eget mauris accumsan malesuada. Nul...", created_at: "2021-01-30 20:50:31.766713000 +0000", updated_at: "2021-01-30 21:04:09.424224000 +0000">> Did you mean? to_yaml
If I loop on 'photo's with:
<% #first2photos.each do |photos| %>
<%= image_tag(#article.photos) %>
<% end %>
I still get the following error:
Can't resolve image into URL: undefined method `to_model'...
Changing that to:
<% #first2photos.each do |photos| %>
<%= image_tag(photos) %>
<% end %>
The page now loads, but shows a broken image icon, with no error. Checking the log in Terminal, I'm not sure I can see where it's attempting to access the photo.
Started GET "/articles/1" for ::1 at 2021-01-31 20:56:58 +0000
Processing by ArticlesController#show as HTML
Parameters: {"id"=>"1"}
Article Load (2.9ms) SELECT "articles".* FROM "articles" WHERE "articles"."id" = $1 LIMIT $2 [["id", 1], ["LIMIT", 1]]
↳ app/controllers/articles_controller.rb:64:in `set_article'
Article Load (1.4ms) SELECT "articles".* FROM "articles" ORDER BY created_at DESC LIMIT $1 [["LIMIT", 2]]
↳ app/controllers/articles_controller.rb:11:in `show'
Rendering layout layouts/application.html.erb
Rendering articles/show.html.erb within layouts/application
Rendered articles/show.html.erb within layouts/application (Duration: 0.4ms | Allocations: 155)
[Webpacker] Everything's up-to-date. Nothing to do
Rendered layout layouts/application.html.erb (Duration: 8.6ms | Allocations: 4208)
Completed 200 OK in 20ms (Views: 9.3ms | ActiveRecord: 4.4ms | Allocations: 6022)

You need to loop over the photos collection to use image_tag for each photo.
<% #first2photos.each do |article| %>
<% article.photos.each do |photo|
<%= image_tag(photo) %>
<% end %>
<% end %>
If you want to show only one image per article then:
<% #first2photos.each do |article| %>
<%= image_tag(article.photos.first) %>
<% end %>
I would change the name first2photos to first2articles to make it less confusing too.

Related

After rendering, browser doesn't refresh the page

I am currently stuck with the search function for blog post.
Controller and html rendering seemed to work well, but I couldn't see any update from browser, Chrome.
From the start of searching scenario, it goes to _navbar.html.erb as below
<%= form_with url: admin_posts_path, method: "get" do %>
<%= text_field_tag :search, params[:search], id: "input-search", placeholder: "Search Posts" %>
<% end %>
, and it goes to posts_controller.rb as below
def index
if params[:search]
#posts = Post.search(params[:search]).all.order('created_at DESC').paginate(per_page: 3, page: params[:page])
puts "&&&&&&&&&&&&&&&&&"
p #posts
puts "###################"
else
#posts = Post.all.order('created_at DESC').paginate(per_page: 3, page: params[:page])
end
end
I found the value of #posts got the right result by using puts through the server log.
However, finally after rendering index.html.erb as below, browser doesn't update any rendered html at all. It just stayed as the current page.
<div class="main">
<section>
<button class="create-button">Create New</button>
<% if #posts.exists? %>
<% #posts.each do |post| %>
<article class="article-summary">
<h1 class="article-title"><%= post.title %></h1>
<p class="article-content"><%= truncate post.body, length: 200 %></p>
<p class="article-created-at"><%= post.created_at.to_time.strftime('%B %e at %l:%M %p') %></p>
<p class="article-command"><button>Edit</button> <%= link_to button_tag("Delete"), admin_post_path(post), method: :delete, data: { confirm: 'Are you sure?' } %></p>
<%= image_tag 'https://placekitten.com/1000/400', class: "article-image" %>
</article>
<% end %>
<%= will_paginate #posts, class: "page"%>
<% else %>
<h2>There is no post</h2>
<% end %>
</section>
</div>
When I saw the server log, it definitely rendered the search results, but I don't have any idea why the browser screen doesn't change anything.
This is the server log
Started GET "/admin/posts?search=nine" for ::1 at 2020-04-29 00:03:15 +1000
Processing by Admin::PostsController#index as JS
Parameters: {"search"=>"nine"}
&&&&&&&&&&&&&&&&&
Post Load (1.1ms) SELECT "posts".* FROM "posts" WHERE (title like '%nine%' OR body like '%nine%') ORDER BY created_at DESC LIMIT $1 OFFSET $2 [["LIMIT", 3], ["OFFSET", 0]]
↳ app/controllers/admin/posts_controller.rb:45:in `p'
#<ActiveRecord::Relation [#<Post id: 9, title: "Blog Post nine", category_id: 1, user_id: 3, tags: "rails", image: nil, body: "Lorem ipsum dolor sit amet, consectetur adipiscing...", created_at: "2020-04-28 12:41:46", updated_at: "2020-04-28 12:41:46">]>
###################
Rendering admin/posts/index.html.erb within layouts/admin/application
Post Exists? (0.4ms) SELECT 1 AS one FROM "posts" WHERE (title like '%nine%' OR body like '%nine%') LIMIT $1 OFFSET $2 [["LIMIT", 1], ["OFFSET", 0]]
↳ app/views/admin/posts/index.html.erb:4
CACHE Post Load (0.0ms) SELECT "posts".* FROM "posts" WHERE (title like '%nine%' OR body like '%nine%') ORDER BY created_at DESC LIMIT $1 OFFSET $2 [["LIMIT", 3], ["OFFSET", 0]]
↳ app/views/admin/posts/index.html.erb:5
Rendered admin/posts/index.html.erb within layouts/admin/application (Duration: 4.4ms | Allocations: 1640)
[Webpacker] Everything's up-to-date. Nothing to do
Rendered partials/_navbar.html.erb (Duration: 0.9ms | Allocations: 909)
Rendered partials/_footer.html.erb (Duration: 0.2ms | Allocations: 75)
Completed 200 OK in 28ms (Views: 15.6ms | ActiveRecord: 1.5ms | Allocations: 14931)
Searching image
#Adwaith gave me the solution.
local: true for the form_with tag really worked for me as below.
<%= form_with url: admin_posts_path, local: true, method: "get" do %>
<%= text_field_tag :search, params[:search], id: "input-search", placeholder: "Search Posts" %>
<% end %>
Thanks #Adwaith

How do I create a dynamic sidebar instead of an index page using Rails 5?

I'm a beginner to Rails 5 and I am working on a NoteTaking app.
Given how notetaking apps are structured, I would like to have a dynamic sidebar with all the posts created appearing on the sidebar (and an possible ability to scroll within the sidebar) instead of having an index page.
Here's how I'd like it to look like (check the image below). While I do see the posts appearing on the sidebar, they're abruptly appearing multiple times as shown.
Here is the relevant code:
application.html.erb
<body>
<div id="sidebar">
<div id="logo">
<%= link_to root_path do %>
<%= image_tag "logo.svg" %>
<% end %>
</div>
<ul>
<li class="category">Notes</li>
<% #posts.all.each do |post| %>
<li><%= post.title %></li>
<% end %>
</ul>
<ul>
<li class="category">Social</li>
<li><%= link_to "Twitter", "#" %></li>
<li><%= link_to "Facebook", "#" %></li>
<li><%= link_to "Email", "#" %></li>
</ul>
<p class="sign_in">Admin Login</p>
</div>
<div id="main_content">
<div id="header">
<p>All Posts</p>
<div class="buttons">
<button class="button"><%= link_to "New Post", new_post_path %></button>
<button class="button">Log Out</button>
</div>
</div>
<% flash.each do |name, msg| %>
<%= content_tag(:div, msg, class: "alert") %>
<% end %>
<%= yield %>
</div>
There was a persistent error that said:
undefined method 'all' for nil:NilClass in the application.html.erb. More specifically here:
<ul>
<li class="category">Notes</li>
<% #posts.all.each do |post| %>
<li><%= post.title %></li>
<% end %>
</ul>
Here's what I tried (no idea whether it is the way to do it..), I added the #posts to be available in all the views by adding it to the application_controller.rb.
class ApplicationController < ActionController::Base
def index
#posts = Post.all.order("created_at DESC")
end
end
I also included the #posts in the new and create methods in the posts_controller.rb like so:
def new
#posts = Post.all.order("created_at DESC")
#post = Post.new
end
# GET /posts/1/edit
def edit
end
# POST /posts
# POST /posts.json
def create
#posts = Post.all.order("created_at DESC")
#post = Post.new(post_params)
respond_to do |format|
if #post.save
format.html { redirect_to #post, notice: 'Post was successfully created.' }
format.json { render :show, status: :created, location: #post }
else
format.html { render :new }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
I don't know how to proceed now. Can you please help me?! No man's land for me...Thanks!
Error stack from the server console:
Started POST "/posts" for 127.0.0.1 at 2018-11-02 16:45:34 -0400
(2.6ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC
↳ /Users/nikhilsamuel/.rvm/gems/ruby-2.5.1/gems/activerecord-5.2.1/lib/active_record/log_subscriber.rb:98
Processing by PostsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"6zdP1vkLjn0BKq4/3qFqozrUhHepyW68Kc+dcJyc4wZMgCdBHBcRawLyXA+8pVnkJelurDFF72O5eruqxujQGw==", "post"=>{"title"=>"hello there", "body"=>"app"}, "commit"=>"Create Post"}
(0.1ms) begin transaction
↳ app/controllers/posts_controller.rb:31
Post Create (2.7ms) INSERT INTO "posts" ("title", "body", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["title", "hello there"], ["body", "app"], ["created_at", "2018-11-02 20:45:35.246718"], ["updated_at", "2018-11-02 20:45:35.246718"]]
↳ app/controllers/posts_controller.rb:31
(3.4ms) commit transaction
↳ app/controllers/posts_controller.rb:31
Redirected to http://localhost:3000/posts/12
Completed 302 Found in 30ms (ActiveRecord: 7.3ms)
Started GET "/posts/12" for 127.0.0.1 at 2018-11-02 16:45:35 -0400
Processing by PostsController#show as HTML
Parameters: {"id"=>"12"}
Post Load (0.3ms) SELECT "posts".* FROM "posts" WHERE "posts"."id" = ? LIMIT ? [["id", 12], ["LIMIT", 1]]
↳ app/controllers/posts_controller.rb:68
Rendering posts/show.html.erb within layouts/application
Rendered posts/show.html.erb within layouts/application (4.2ms)
Completed 500 Internal Server Error in 633ms (ActiveRecord: 0.3ms)
ActionView::Template::Error (undefined method `each' for nil:NilClass):
19:
20: <ul>
21: <li class="category">Notes</li>
22: <% #posts.each do |post| %>
23: <li><%= post.title %></li>
24: <% end %>
25: </ul>
app/views/layouts/application.html.erb:22:in `_app_views_layouts_application_html_erb__3194645343067756970_70256024775560'
Started GET "/posts/new" for 127.0.0.1 at 2018-11-02 16:45:40 -0400
Processing by PostsController#new as HTML
Rendering posts/new.html.erb within layouts/application
Rendered posts/_form.html.erb (30.6ms)
Rendered posts/new.html.erb within layouts/application (37.1ms)
Post Load (0.4ms) SELECT "posts".* FROM "posts" ORDER BY created_at DESC
↳ app/views/layouts/application.html.erb:22
Completed 200 OK in 84ms (Views: 73.9ms | ActiveRecord: 0.4ms)
Started GET "/posts/new" for 127.0.0.1 at 2018-11-02 16:45:41 -0400
Processing by PostsController#new as HTML
Rendering posts/new.html.erb within layouts/application
Rendered posts/_form.html.erb (1.9ms)
Rendered posts/new.html.erb within layouts/application (5.0ms)
Post Load (0.2ms) SELECT "posts".* FROM "posts" ORDER BY created_at DESC
↳ app/views/layouts/application.html.erb:22
Completed 200 OK in 45ms (Views: 39.1ms | ActiveRecord: 0.2ms)
Don't rely on an instance variable in your application layout, that's simply not how it should be done.
Instead add a helper method, e.g. posts_for_navigation, into your ApplicationHelper and get the posts from there. This will mean a lot less code in the controllers.
I've run it with the same code as you and come up with a few things;
First, your application.html.erb doesn't have a closing body tag, not sure if that's just a mistype.
Your html needs a change as mine threw an error when there are no actual posts created so I wrapped the loop in an unless statement;
<ul>
<li class="category">Notes</li>
<% unless #posts.nil? %>
<% #posts.all.each do |post| %>
<li><%= post.title %></li>
<% end %>
<% end %>
</ul>
As for the application_controller.rb, adding an index method there doesn't affect the index view of your models. Get right rid of that and leave the application_controller empty as it was. The easiest way to accomplish what you want is to just query the database in application.html.erb ie. So really, remove all the extra #posts variable you wrote into the controllers.
<ul>
<li class="category">Notes</li>
<% Post.all.reverse.each do |post| %>
<li><%= post.title %></li>
<% end %>
</ul>
This just makes a query from each loaded page, instead of using a variable from a controller. No doubles, no nil calls.
In my opinion, the best way to do this would be to create a fragment that renders your sidebar with an #sidebar_posts variable or something similar. But that's probably for the further down the line.
Cheers and good luck!
EDIT:
Saw the other answer after posting, to combine the two you could change the html to;
<ul>
<li class="category">Notes</li>
<% posts_for_sidebar.each do |post| %>
<li><%= post.title %></li>
<% end %>
and then add the following method into the application_helper.rb as suggested;
def posts_for_sidebar
#sidebar_posts = Post.all.reverse
end
But you still need to remove all the extra #post instance variables in the controllers.

view does not render when using a form_with, with a url and existing controller action in ROR

When I attempt to submit a post request using form_with and a custom url pointing to an existing controller action, the view does not render.
I am trying to follow a tutorial which shows the differences between form_for and form_tag in ROR, but trying to use form_with instead because the former are going to be deprecated. It all works fine using the form_tag.
The Rails Guides for form helpers only shows form_for and form_tag.
The ROR API docs does show some examples with form_with, but I am not connecting the dots.
<!-- index.html.erb -->
<%= form_with(url: create_users_path) do |f| %>
<%= f.text_field :name, placeholder: "Your Name" %>
<%= f.number_field :age, placeholder: "Your Age" %>
<%= f.submit "Create Profile" %>
<% end %>
and
# routes.rb
get 'users' => 'welcome#users'
post 'create_users' => 'welcome#users'
and
# welcome_controller.rb
def users
if params[:name] != nil
user = User.create(name: params[:name], age: params[:age])
end
#users = User.all
end
and
<!--users.html.erb-->
<table border="2">
<tr>
<th>Name</th>
<th>Age</th>
</tr>
<% #users.each do |user| %>
<tr>
<td><%= user.name %></td>
<td><%= user.age %></td>
</tr>
<% end %>
</table>
<br>
<%= link_to "Return to Index", root_path %>
My users table updates with the data sent in the form, but I am left on my index.html.erb view instead of at users.html.erb where I expect, as the .create active record call is in the users action.
And here are my server logs from the POST request where welcome/users.html.erb is said to have been rendered (browser doesn't update.) A GET will render the page in the browser.
Started POST "/create_users" for 127.0.0.1 at 2018-08-05 22:18:26 -0400
Processing by WelcomeController#users as JS
Parameters: {"utf8"=>"✓", "authenticity_token"=>"upoeRgVioYXs+Z+vsyBdg4CnXrSTOMCzPFXSHUKT2IlrVMDtvnf8UD7yJkPMYw0zkwihmPvY3Yq0BlG7RFsIIQ==", "name"=>"testy testerson", "age"=>"28", "commit"=>"Create Profile"}
(0.1ms) begin transaction
SQL (2.4ms) INSERT INTO "users" ("name", "age", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["name", "testy testerson"], ["age", 28], ["created_at", "2018-08-06 02:18:26.466212"], ["updated_at", "2018-08-06 02:18:26.466212"]]
(3.2ms) commit transaction
Rendering welcome/users.html.erb within layouts/application
User Load (0.2ms) SELECT "users".* FROM "users"
Rendered welcome/users.html.erb within layouts/application (4.3ms)
Completed 200 OK in 147ms (Views: 56.8ms | ActiveRecord: 6.7ms)
Started GET "/users" for 127.0.0.1 at 2018-08-05 22:19:19 -0400
Processing by WelcomeController#users as HTML
Rendering welcome/users.html.erb within layouts/application
User Load (0.3ms) SELECT "users".* FROM "users"
Rendered welcome/users.html.erb within layouts/application (2.3ms)
Completed 200 OK in 60ms (Views: 51.1ms | ActiveRecord: 0.3ms)
I am pretty sure that having the create and show in the same action is not a best practice...just trying to get a better understanding of rails. What am I missing about the routes/controller/views relationship?
I am using rails versrion 5.1.6

Rails render not opening new page with searchkick

I'm trying to make a search kick results page. However when i click search the console states i've got the correct id but the results page isnt opening.
I have this for my controller
def search
#events = Newevent.search params[:search]
render 'events/results'
end
I also have this as my search form
<div class="input-group input-group-lg">
<%= text_field_tag :search, params[:search], class: "form-control", autocomplete: "off" %>
<div class="input-group-btn">
<%= submit_tag "Search", class: "btn btn-primary" %>
</div>
</div>
<% end %>
And this is inside the results html.erb
<% #events.each do |event| %>
<h1>Test</h1>
<%= event.eventname %>
<% end %>
Heres what the console states when i start the search
Started GET "/search_events?utf8=%E2%9C%93&search=capital&commit=Search" for ::1 at 2015-11-21 15:18:33 +0000
Processing by NeweventsController#search as JS
Parameters: {"utf8"=>"✓", "search"=>"capital", "commit"=>"Search"}
User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT 1 [["id", 2]]
Newevent Search (9.8ms) curl http://localhost:9200/newevents_development/_search?pretty -d '{"query":{"dis_max":{"queries":[{"match":{"_all":{"query":"capital","operator":"and","boost":10,"analyzer":"searchkick_search"}}},{"match":{"_all":{"query":"capital","operator":"and","boost":10,"analyzer":"searchkick_search2"}}},{"match":{"_all":{"query":"capital","operator":"and","boost":1,"analyzer":"searchkick_search","fuzziness":1,"prefix_length":0,"max_expansions":3,"fuzzy_transpositions":true}}},{"match":{"_all":{"query":"capital","operator":"and","boost":1,"analyzer":"searchkick_search2","fuzziness":1,"prefix_length":0,"max_expansions":3,"fuzzy_transpositions":true}}}]}},"size":100000,"from":0,"fields":[]}'
Newevent Load (0.5ms) SELECT "newevents".* FROM "newevents" WHERE "newevents"."id" = 20
Rendered events/results.html.erb within layouts/application (1.6ms)
Rendered layouts/_navigation.html.erb (0.1ms)
Rendered layouts/_messages.html.erb (0.1ms)
Rendered layouts/_footer.html.erb (0.0ms)
Completed 200 OK in 93ms (Views: 79.5ms | Searchkick: 9.8ms | ActiveRecord: 1.0ms)
Base on your server's log, I think you setup your search form as a remote form (you will see you have remote: true in your form_for tag)
Processing by NeweventsController#search as JS
Do you see text: as JS in the above line. That's because you submit a remote form. That means when you submit your form, the form will call ajax to server wait for server to return a js code to run on client side.
To solve your problem, just remove remote: true in your form_for tag, and everything will be ok ;)

"invalid-request-cookie" error

So for some reason I'm getting a "invalid-request-cookie" when trying to submit a ReCaptcha. I'm using the ReCaptcha gem.
What am I doing wrong?
Also, I have my ReCaptcha public and private keys in my bash_profile so that shouldn't be an issue.
UsersStepsController.rb
class UserStepsController < ApplicationController
def show
end
def update
#user = current_user
captcha_message = "The data you entered for the CAPTCHA wasn't correct. Please try again"
if !verify_recaptcha(message: captcha_message)
render :add_recaptcha
else
redirect_to root_path and return
end
end
def add_recaptcha
#user = current_user
end
end
Routes.rb
patch '/user_steps', to: 'user_steps#update', as: 'update_user_steps'
resources :user_steps, except: [:update]
get '/add_recaptcha', to: 'user_steps#add_recaptcha'
user_steps/add_captcha.html.erb
<fieldset class="clearfix">
<div class="g-recaptcha" data-sitekey="6LeUQ_xxxx_etc"></div>
<div align="center"><%= recaptcha_tags :public_key => ENV['RECAPTCHA_PUBLIC_KEY'] %></div>
<%= form_for(#user, {url: update_user_steps_path(id: #user.to_param)}) do |f| %>
<br>
<%= f.submit "Done", class: "styling" %>
<% end %>
</div>
</fieldset>
Update Logs:
Started PATCH "/user_steps?id=35" for 127.0.0.1 at 2014-11-26 11:55:52 -0500
Started PATCH "/user_steps?id=35" for 127.0.0.1 at 2014-11-26 11:55:52 -0500
Processing by UserStepsController#update as HTML
Processing by UserStepsController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"sEOPI8KVuXLPSLjXVajF8QcWeLcUpibgHq6hHqgtwGA=", "commit"=>"Done", "id"=>"35"}
Parameters: {"utf8"=>"✓", "authenticity_token"=>"sEOPI8KVuXLPSLjXVajF8QcWeLcUpibgHq6hHqgtwGA=", "commit"=>"Done", "id"=>"35"}
User Load (0.8ms) SELECT "users".* FROM "users" WHERE "users"."id" = 35 ORDER BY "users"."id" ASC LIMIT 1
User Load (0.8ms) SELECT "users".* FROM "users" WHERE "users"."id" = 35 ORDER BY "users"."id" ASC LIMIT 1
Rendered layouts/_messages.html.erb (0.1ms)
Rendered layouts/_messages.html.erb (0.1ms)
Rendered layouts/headers/_header_sign_up_step2.html.erb (0.2ms)
Rendered layouts/headers/_header_sign_up_step2.html.erb (0.2ms)
Rendered user_steps/add_recaptcha.html.erb within layouts/application (28.2ms)
Rendered user_steps/add_recaptcha.html.erb within layouts/application (28.2ms)
Completed 200 OK in 919ms (Views: 800.4ms | ActiveRecord: 0.8ms)
Completed 200 OK in 919ms (Views: 800.4ms | ActiveRecord: 0.8ms)
Here is your answer :) You need to include that inside your form unless the value won't be saved!
<fieldset class="clearfix">
<%= form_for(#user, {url: update_user_steps_path(id: #user.to_param)}) do |f| %>
<div align="center"><%= recaptcha_tags :public_key => ENV['RECAPTCHA_PUBLIC_KEY'] %></div>
<br>
<%= f.submit "Done", class: "styling" %>
<% end %>
</div>
</fieldset>

Resources