Pass the devise user path in a partial - ruby-on-rails

I'm trying to create a sidebar menu with the below information:
# app/controllers/users_controller.rb
def show
#user = User.friendly.find(params[:id])
end
# config/routes.rb
get "/user/:id", to: "users#show"
I have the link from the dropdown menu to the current_user path:
<!-- app/views/layouts/_dropdown_menu.html.erb -->
<%= link_to "My Account", current_user %>
This is how I create the sidebar menu:
<!-- app/views/layouts/dashboard.html.erb -->
<%= render "shared/sidebar_panel" %>
<!-- app/views/shared/_sidebar_panel.html.erb -->
<%= render "shared/nav" %>
<!-- app/views/shared/_nav.html.erb -->
<% SidebarMenu.all.each do |entry| %>
<% if entry[:group_title].present? %>
<li class="nav-title"><%= entry[:group_title]%></li>
<% end %>
<%= render partial: 'shared/nav_submenu',
collection: entry[:children],
as: :sub_menu,
locals: {parents: []} %>
<% end %>
<!-- app/views/shared/_nav_submenu.html.erb -->
<li>
<a href="<%= sub_menu[:href] %>">
<span><%= sub_menu[:title] %></span>
<% if sub_menu[:subtitle].present? %>
<span class="<%= sub_menu[:subtitle_class] %>">
<%= sub_menu[:subtitle] %>
</span>
<% end %>
</a>
<% if sub_menu[:children].present? %>
<ul>
<%= render partial: 'shared/nav_submenu',
collection: sub_menu[:children],
as: :sub_menu,
locals: {parents: parents + [sub_menu]} %>
</ul>
<% end %>
</li>
I have a SidebarMenu model and I've added current_user path:
# app/models/sidebar_menu.rb
class SidebarMenu
class << self
include Rails.application.routes.url_helpers
end
def self.all
[
{
group_title: "Account & Contact",
children: [
{
href: "#",
title: "Account",
icon: "...",
children: [
{
href: current_user,
title: "My Account"
}
]
},
# ...
]
}
]
end
end
But it raises an error message:
undefined local variable or method `current_user' for SidebarMenu:Class
Can anyone advise me how I can fix this?

This is how current_user method is set up by Devise: current_user is a controller method included by devise and loaded in ActionController::Base class. It is also available in the views because it is a helper method which gets included in ActionView::Base. current_user is not a url helper and it returns a User model instance which link_to can turn into a url automatically.
current_user is outside of the scope of SidebarMenu class. To fix it, just pass it as an argument:
class SidebarMenu
def self.all user
[{ href: user, title: "My Account" }]
end
end
# in the view or controller
SidebarMenu.all(current_user) # => [{ href: #<User:0x0000563cc7c69198>, title: "My Account" }]
I think, a better approach is to use menu class as an object. It is more flexible and easier to use:
class Menu
include Rails.application.routes.url_helpers
def initialize(user:)
#user = user
end
def user_menu
{
group_title: "Account",
# NOTE: use url helper to return a path instead of a `User` model
children: [{ href: user_path(user), title: "My Account" }]
}
end
def sidebar_menu
{
group_title: "Main",
children: [{ href: root_path, title: "Home" }]
}
end
def all
[sidebar_menu, user_menu]
end
private
attr_reader :user
end
Use it in the view:
Menu.new(user: current_user).user_menu[:children]
# => [{ href: "/users/1", title: "My Account" }]
You can also set up a helper method:
# in the ApplicationController
private
def menu
#menu ||= Menu.new(user: current_user)
end
helper_method :menu
# in the view
menu.user_menu[:children] # => [{ href: "/users/1", title: "My Account" }]
# TODO:
# menu.sidebar_menu
# menu.all.each do |group|
# group[:group_title]
# ...
# end
https://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#method-i-link_to
https://api.rubyonrails.org/classes/AbstractController/Helpers/ClassMethods.html#method-i-helper_method
List url helpers: Rails.application.routes.named_routes.helper_names
List controller helpers: ApplicationController._helper_methods

Related

How can I display my search results in rails?

When I write city in field and click button, on page has to be that name of city and another. In my case every time name is New York. When I write for example Las Vegas my link is http://localhost:3000/?query=Las+Vegas&commit=Search, the data on the page is about New York.
class HomeController < ApplicationController
def index
require 'net/http'
require 'json'
#params = {
:access_key => "1dbc1a3aa6b2e76a0c8eda1cba0c9c8b",
:query => "New York"
}
#uri = URI("http://api.weatherstack.com/current?access_key=1dbc1a3aa6b2e76a0c8eda1cba0c9c8b&query=#{#params[:query]}")
#uri.query = URI.encode_www_form(#params)
#json = Net::HTTP.get(#uri)
#api_response = JSON.parse(#json)
if #params[:query].empty?
#city = "Enter city"
#temperature = "(in English)"
else
#city = " #{#api_response['location']['name']}"
#temperature = "#{#api_response['current']['temperature']}°"
end
end
end
routes.rb
Rails.application.routes.draw do
root 'home#index', :as => 'search'
end
index.html.erb
<div class="main">
<h1 class="weather">Weather</h1>
<%= form_with(url: search_path, method: "get", local: true) do %>
<%= text_field_tag(:query) %>
<%= submit_tag("Search",class: "btn btn-primary") %>
<% end %>
<div class="city"> <h1><%= #city %> <h5><%= #temperature %></h5></h1> </div>
</div>
It looks like you have hardcoded New York in your params.
#params = {
:access_key => "1dbc1a3aa6b2e76a0c8eda1cba0c9c8b",
:query => "New York"
}
So you need to change this to be something like:
#params = {
:access_key => "1dbc1a3aa6b2e76a0c8eda1cba0c9c8b",
:query => params[:query]
}

Why am I getting a ActionView::Template::Error (Nil location provided. Can't build URI) error in Heroku but not in development?

I'm building a simple app that consumes the Open Weather Map API and returns some weather parameters and a gif that corresponds to the current weather. Users are able to search for a city's current weather.
Everything is working fine locally but I've deployed to Heroku and when I search for a city it throws an error. The Heroku logs show ActionView::Template::Error (Nil location provided. Can't build URI My code is below.
The error occurs on this line: <div class="gif-container"><%= image_tag(find_gif_url, class: "gif") %>
views/current_weather.html.erb
<div class="page-wrapper">
<h1 class="title">The weather in GIFs</h1>
<div class="search">
<%= form_tag(current_weather_forecasts_path, method: :get) do %>
<%= text_field_tag :q, nil, placeholder: "Enter a city", class: "search-field" %>
<%= button_tag type: 'submit', class: "search-button" do %>
<i class="fas fa-search"></i>
<% end %>
<% end %>
</div>
<% if #forecasts_facade.invalid_city? %>
<p>Please use a valid city name!</p>
<% elsif #forecasts_facade.missing_city? %>
<p>Please type in a city name!</p>
<% elsif #forecasts_facade.forecast == {} %>
<% else %>
<p class="weather-description"><%= "#{#city.capitalize}: #{#forecasts_facade.description}" %></p>
<div class="gif-container"><%= image_tag(find_gif_url, class: "gif") %>
<span class="temperature weather-attribute"><%= "#{#forecasts_facade.temperature}°C" %></span>
<span class="wind weather-attribute"><%= "wind:#{(#forecasts_facade.wind * 3.6).to_i}km/h" %></span> <!-- converts to km/hr -->
<span class="humidity weather-attribute"><%= "humidity:#{#forecasts_facade.humidity}%" %></span>
</div>
<% end %>
</div>
forecasts_controller.rb
class ForecastsController < ApplicationController
TOKEN = Rails.application.credentials.openweather_key
def current_weather
#city = params[:q]
if #city.nil?
#forecast = {}
else
#forecast = OpenWeatherApi.new(#city, TOKEN).my_location_forecast
end
#forecasts_facade = ForecastsFacade.new(#forecast)
end
end
helpers/forecasts_helper.rb
module ForecastsHelper
GIFS = {
thunder:
{codes: [200, 201, 202, 210, 211, 212, 221, 230, 231, 232],
urls: %w(
https://media.giphy.com/media/26uf5HjasTtxtNCqQ/giphy.gif
https://media.giphy.com/media/vS09bj1KrXwje/giphy.gif
)},
light_rain:
{codes: [300, 301, 302, 310, 311, 312, 313, 314, 321, 500, 501, 520, 521],
urls: %w(
https://media.giphy.com/media/xT9GEz2CeU9uaI2KZi/giphy.gif
https://media.giphy.com/media/k28n1OPefBEeQ/giphy.gif
https://media.giphy.com/media/H1eu9Vw957Rfi/giphy.gif
https://media.giphy.com/media/Jyeo8wBpdwpry/giphy.gif
https://media.giphy.com/media/14d8cRr25KPxbG/giphy.gif
)},
heavy_rain:
{codes: [502, 503, 504, 522, 531, 511],
urls: %w(
https://media.giphy.com/media/1Yfxps0AHRYBR2tK2G/giphy.gif
https://media.giphy.com/media/7zSIC0roM238CVTS4u/giphy.gif
https://media.giphy.com/media/l0Expn6D0D3g9NExq/giphy.gif
)},
}
def find_gif_url
GIFS.each do |key, value|
if value[:codes].include? #forecasts_facade.weather_code
return value[:urls].sample
end
end
end
end
facades/forecasts_facade.rb
class ForecastsFacade
attr_accessor *%w(
forecast
).freeze
def initialize(forecast)
#forecast = forecast
end
def temperature
#temperature = forecast.dig('main', 'temp').to_i - 273
end
def weather_code
#weather_code = forecast.dig('weather', 0, 'id').to_i
end
def description
#description = forecast.dig('weather', 0, 'description')
end
def wind
#wind = forecast.dig('wind', 'speed').to_i
end
def humidity
#humidity = forecast.dig('main', 'humidity')
end
def invalid_city?
forecast.dig('cod').to_i == 404
end
def missing_city?
forecast.dig('cod').to_i == 400
end
end
services/open_weather_api.rb
class OpenWeatherApi
include HTTParty
base_uri "http://api.openweathermap.org"
def initialize(city, appid)
#options = { query: { q: city, APPID: appid } }
end
def my_location_forecast
self.class.get("/data/2.5/weather", #options)
end
end
Your call to this method:
def find_gif_url
GIFS.each do |key, value|
if value[:codes].include? #forecasts_facade.weather_code
return value[:urls].sample
end
end
end
Is returning nil. That is to say that your search for an entry in the GIFS hash did not actually find a result. Consider the value of #forecasts_facade.weather_code and why it might not be found in the value of value[:codes]. Adding some code to handle the case where an entry in GIFS was not found is probably a good idea.
As an aside, I might recommend using Enumerable#find instead of iterating over GIFS and returning manually. That would be "idiomatic Ruby", or the "Ruby way to do it".

Values of a book saved from amazon have {:value=>""} around it

I'm making an application where the user can search Amazon (with Vacuum) through my application for books, then be able to record the data of the book to their library.
When you search for a book, it goes through every result and puts each in a thumbnail. In every thumbnail there is a button that opens a modal with a form with hidden tags. When the user clicks the submit button, the book's title is saved into a new book. The only problem is that the title is saved like {:value=>"the title of the book that was saved"}
Here is the part of new.html.erb which has the search box:
<%= form_tag({controller: "books", action: "new"}, method: "get", id: "search-form") do %>
<%= text_field_tag :keywords, params[:keywords], placeholder: "Search for a book", class: "form-control" %>
<% end %>
Here is the part of new.html.erb which has the hidden form:
<% #results.each do |result| %>
…
<%= form_for #book do |f|%>
<%= hidden_field_tag :title, class: 'form-control', value: result.name %>
<%= f.submit "Add book", class: "btn btn-default green-hover" %>
<% end %>
…
<% end %>
Here are the new and create actions in my controller:
def new
#book = current_user.books.build if logged_in?
# Search actions
if params[:keywords]
request = Vacuum.new
request.configure(
aws_access_key_id: ENV['AWS_ACCESS_KEY_ID'],
aws_secret_access_key: ENV['AWS_SECRET_ACCESS_KEY'],
associate_tag: 'my associate tag is here'
)
keywords = params[:keywords]
params = {
'SearchIndex' => 'Books',
'Keywords'=> keywords,
'ResponseGroup' => "ItemAttributes,Images"
}
raw_results = request.item_search(query: params)
hashed_results = raw_results.to_h
#results = []
hashed_results['ItemSearchResponse']['Items']['Item'].each do |item|
result = OpenStruct.new
result.title = item['ItemAttributes']['Title']
result.url = item['DetailPageURL']
result.image_url = item['MediumImage']['URL']
result.author = item['ItemAttributes']['Author']
result.pages = item['ItemAttributes']['NumberOfPages']
#results << result
end
end
end
def create
#book = #list.books.build(book_params)
if #book.save
flash[:success] = #book.title + "was added to your log."
redirect_to list_path(#book.list_id)
else
render 'books/new'
end
end
I tried to use gsub within book.rb to fix it, but that only changed the text within the flash message and it still saved as {:value=>"the title of the book that was saved"}.
after_create :init
private
def init
puts "Init was called!"
self.title.gsub!('{:value=>"', " ")
self.title.gsub!('"}', " ")
end
How can I change it so that it doesn't save the title with the {:value=>} around it?
I don't think the hidden field tag is right.
<%= hidden_field_tag :title, class: 'form-control', value: result.name %>
Try
<%= hidden_field_tag :title, result.name %>
Your title is being saved as a hash not a string. Use hash accessing methods:
t = title[:value]
puts t #=> "the tile of the book that was saved"

Pass variable to a Fancybox in Rails with Content

I have this link in Rails:
<%= link_to "Add to Journal", add_post_journal_path(post), :method => :put %>
However I want transform this link to show a fancybox with the content listing my content to choose. First, I use this code:
<%= link_to "fancy", "#add_post", :class=>"fancybox" %>
but I have errors, because I want pass the actual post to fancybox, so I'm using this code: in add_post.html.erb:
<h1>Escolha o Jornal que deseja adicionar:</h1>
<ul>
<% current_user.journals.each do |journal| %>
<li><%= link_to journal.name,add_post_complete_journal_path(journal),:remote=>true %> </li>
<% end %>
</ul>
and my controller is:
def add_post
#journal_post = JournalsPosts.new
session[:post_add] = params[:id]
end
def add_post_complete
#journal_post = JournalsPosts.create(:post_id => session[:post_add],:journal_id => params[:id])
respond_with #journal_post
end
How can I transform this code to use my content in my fancybox?
Add on your action add_post the next respond with js:
def add_post
#journal_post = JournalsPosts.new
session[:post_add] = params[:id]
respond_to do |format|
format.js
end
end
Add on a file on your views add_post.js.erb with the next content:
$.fancybox('<%= escape_javascript(render(:partial => 'path_to/add_post'))%>',
{
openEffect: "fade",
closeEffect: "fade",
autoSize: true,
minWidth: 480,
scrolling: 'auto',
});
For example, you have add a partial _add_post.html.erb on your views. Now inside this partial you can write your code view:
#code for your view inside partial `add_post.html.erb`
<%= #journal_post %>
<h1>Escolha o Jornal que deseja adicionar:</h1>
<ul>
.
.
Regards!

link_to edit page default path?

I'm using Rails3 to build a simple customer information page (in table format). On this page user can edit each customer's detailed information. It's possible for each customer to have multiple records. I use link_to to get to the edit page:
<td class="edit" id="edit">edit
<%= link_to 'edit', :action => :edit, :cust_id => ci.cust_id %>
</td>
edit.html.erb:
<h1>Editing cust</h1>
<%= form_for(#cust_info) do |cust| %>
Customer: <%= cust.text_field :cust_schema %>
<%= cust.submit "Save" %>
<% end%>
In my controller, I have this:
def edit
cust_id = params[:cust_id]
#cust_info = CustInfo.find(:all, :conditions => ["cust_id = ?", cust_id])
end
The customer info page shows right. When I click the edit link, I got the error message:
ActionView::Template::Error (undefined method `cust_info_cust_info_path' for #<#<Class:0x7fb0857ce7b8>:0x7fb0857ca780>):
1: <h1>Editing cust</h1>
2:
3: <%= form_for(#cust_info) do |cust| %>
4: Customer: <%= cust.text_field :cust_schema %>
5: <%= cust.submit "Save" %>
6: <% end%>
app/views/track/edit.html.erb:3:in `_app_views_track_edit_html_erb___102324197_70198065248580_0'
Where does `cust_info_cust_info_path' come from?
EDIT: here is the code in the controller:
class TrackController < ApplicationController
def display
end
def information
end
def customerinfo
#cust_info = CustInfo.find(:all, :order=>"cust_id")
#cust_info.each do |ci|
if ci.upload_freq == 'W'
ci.upload_freq = 'Weekly'
elsif ci.upload_freq == 'M'
ci.upload_freq = 'Monthly'
end
end
end
def edit
cust_id = params[:cust_id]
#cust_info = CustInfo.find(:all, :conditions => ["cust_id = ?", cust_id])
end
end
end
Change #cust_info = CustInfo.find(:all, :conditions => ["cust_id = ?", cust_id])
to
#cust_info = CustInfo.find(cust_id)

Resources