I am new to rails 3, I would like to add (:target => "_blank") to link_to helper below
link_to "GOOGLE", 'http://www.google.com', class: "btn btn-large btn-primary"
But I would like to use the application_helper to define link_to method.
How do I define the link_to methd in application_helper?
How do I pass the class: "btn btn-large btn-primary" in the link_to method?
Thank you for your assistance...
Why would you want to override link_to? It's already defined in Rails, just use it like this :
link_to "GOOGLE", "http://www.google.com", target: "_blank", class: "btn btn-large btn-primary"
Edit: OK, understood. I'd advise against overriding such a common method so create another one :
def link_to_blank(body, url_options = {}, html_options = {})
link_to(body, url_options, html_options.merge(target: "_blank"))
end
It should do the trick
Adding to Anthony's answer, this more closely resembles Rails' link_to implementation, including support for blocks and passing no parameters:
def link_to_blank(name = nil, options = nil, html_options = nil, &block)
target_blank = {target: "_blank"}
if block_given?
options ||= {}
options = options.merge(target_blank)
else
html_options ||= {}
html_options = html_options.merge(target_blank)
end
link_to(name, options, html_options, &block)
end
Up to now for Rails 7, I suggest a more elegant way according to Rails's implementation of link_to:
def link_to(name = nil, options = nil, html_options = nil, &block)
html_options, options, name = options, name, block if block_given?
link_to(name, options, (html_options || {}).merge(target: '_blank'))
end
Related
I'm having a trouble when I try to use Simple Form gem for upload video. I'm using ActiveStorage and local storage for this.
My form looks like this:
= simple_form_for #film do |f|
= f.error_notification
= f.input :title, as: :string
= f.input :description, as: :string
= f.input :cover_img, as: :file
= f.input :film_link, as: :file, direct_upload: true
= f.button :submit
= link_to 'back', :back, class: 'btn btn-secondary'
I've followed instruction on here https://edgeguides.rubyonrails.org/active_storage_overview.html
So I've included js and css files in my app. But that won't work. It looks like there's some troubles with passing direct_upload: true via simple_form.
I've also find article https://phase2online.com/blog/2018/10/03/easily-upload-files-with-active-storage-in-rails-5-2/ and pull git repo from here
An this works on when you'll use form_for on your _form. When I change form to use simple_form gem(instead of form_form use simple_form_for) it won't work.
Anyone have an idea why this is not working please?
I use ruby 2.6.3 and Rails 5.2.3 and simple_form (5.0.1)
There're is the way to make this work.
We can change f.input to f.file_field as hashrocket suggest - but then validation of simple form will not work, and perhaps we have to add class to this input plus extra div before.
We can add html attribute to the f.input.
For me this is working I hope it will help someone else too.
= simple_form_for #film do |f|
= f.error_notification
= f.input :title, as: :string
= f.input :description, as: :string
= f.input :cover_img, as: :file, input_html: { data: { direct_upload_url: '/rails/active_storage/direct_uploads' } }
= f.input :film_link, as: :file, input_html: { data: { direct_upload_url: '/rails/active_storage/direct_uploads' } }
= f.button :submit
= link_to 'back', :back, class: 'btn btn-secondary'
These days (rails 6.x), you shouldn't need to specify as: file (simple form should figure this out via reflection) and you can just pass direct_upload: true to input_html:
= simple_form_for #film do |f|
= f.error_notification
= f.input :title, as: :string
= f.input :description, as: :string
= f.input :cover_img, input_html: { direct_upload: true }
= f.input :film_link, input_html: { direct_upload: true }
= f.button :submit
= link_to 'back', :back, class: 'btn btn-secondary'
Verify it's doing the right thing by looking at the generated html. You should see an attribute like this on each input which is of type="file":
data-direct-upload-url="https://<your app server>/rails/active_storage/direct_uploads"
#anka's suggestion to create a custom input type is a good one, but you could also edit the default simple form wrappers for file types if you know all your files will be direct uploads to S3.
I would suggest to simply add a custom input for that to avoid repetition within your view files. Put this in the file app/inputs/direct_upload_file_input.rb:
# frozen_string_literal: true
class DirectUploadFileInput < SimpleForm::Inputs::FileInput
def input_html_options
super.merge({ direct_upload: true })
end
end
Everything was working fine till I tried defining gravatar_for and calling it. user.email.downcase is nil class. Below is what I am working with. Let me know if you need any other information.
I see when running localhost at url http://localhost:3000/users/1
NoMethodError in Users#show
`Showing /Users/nathandewaele/Desktop/workspce/static_pages/app/views/users/show.html.erb where line #6 raised:
undefined method `downcase' for nil:NilClass`
extracted source around line 5
gravatar_id = Digest::MD5::hexdigest(user.email.downcase)
`Rails.root: /Users/nathandewaele/Desktop/workspce/static_pages
Application Trace | Framework Trace | Full Trace
app/helpers/users_helper.rb:5:in `gravatar_for'
app/views/users/show.html.erb:6:in `_app_views_users_show_html_erb___4114710587947303689_70365956197180'
Request
Parameters:
{"id"=>"1"}
Toggle session dump
Toggle env dump
Response
Headers:
None`
app/helpers/users_helper.rb
```rb
module UsersHelper
# Returns the Gravatar for the given user.
def gravatar_for(user, options = { size: 80 })
gravatar_id = Digest::MD5::hexdigest(user.email.downcase)
size = options[:size]
gravatar_url = "https://secure.gravatar.com/avatar/#{gravatar_id}?s=#{size}"
image_tag(gravatar_url, alt: user.name, class: "gravatar")
end
end
```
app/controllers/users_controller.rb
```ruby
class UsersController < ApplicationController
def show
#user = User.find(params[:id])
end
def new
#user = User.new
end
end
```
app/db/schema.rb
```ruby
ActiveRecord::Schema.define(version: 20171108202327) do
create_table "users", force: :cascade do |t|
t.string "name"
t.string "email"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "password_digest"
t.index ["email"], name: "index_users_on_email", unique: true
end
end
```
app/controllers/config/routes.rb
```ruby
Rails.application.routes.draw do
# get '/new', to: 'users#new'
get '/show', to: 'users#show'
get '/help', to: 'static_pages#help'
get '/about', to: 'static_pages#about'
get '/contact', to: 'static_pages#contact'
get '/signup', to: 'users#new'
resources :users
end
```
app/views/users/show.html.erb
```erb
<% provide(:title, #user.name) %>
<div class="row">
<aside class="col-md-4">
<section class="user_info">
<h1>
<%= gravatar_for #user %>
<%= #user.name %>
</h1>
</section>
</aside>
</div>
```
screenshot of error
Had the same issue, resolved when I updated /app/helpers/users_helper with the code:
# Returns the Gravatar for the given user.
def gravatar_for(user)
gravatar_id = Digest::MD5::hexdigest(user.email.downcase)
gravatar_url = "https://secure.gravatar.com/avatar/#{gravatar_id}"
image_tag(gravatar_url, alt: user.name, class: "gravatar")
end
(as shown in Listing 7.9)
I was having this same issue, which was hard to trace! As mentioned above, an email was not being sent to the database. My problem appeared to resolve itself after I changed code in my model/users.rb file that I was confusing myself with:
before_save { self.email = email.downcase }.
Before I had used before_save { self.email = email.downcase! }. Validation is located in Chapter 6 of the Rails Tutorial. Somehow I was confusing email.downcase! with self.email = email.downcase.
This still leaves the mystery of why an account was created without an email, instead of an error preventing me from proceeding...
For some reason, when I submit my form and update my user profile record, my user profile records have all the other columns updated to nil for some reason.
Lets say User.last.user_profile has an attribute "linkedin_url" and it is set to "www.yahoo.com". Once I submit the form, the User :phone number, and UserProfile :work_address, :work_zipcode gets updated, but the "linkedin_url" gets set to nil. IDK why!
class UserProfilesController < ApplicationController
def update
#user = User.last
if #user.update(user_profile_params)
respond_to do |format|
format.html {
redirect_to user_profile_path(#user)
}
format.json {
render :show, status: :ok, location: #preference
}
end
end
end
def user_profile_params
params.require(:user).permit( :phone_number, user_profile_attributes: [:work_address, :work_zipcode])
end
form
= form_for #user, url: user_profile_path(#user), method: :put do |f|
= f.fields_for :user_profile do |ff|
= ff.label :work_address
%br
= ff.text_field :work_address
%br
= ff.label :work_zipcode
%br
= ff.text_field :work_zipcode
%br
= f.label :phone_number
%br
= f.text_field :phone_number
%br
= f.submit "Submit", class: "btn"
def user_profile_params
params.require(:user).permit(
:phone_number,
user_profile_attributes: [:work_address, :work_zipcode] # ⇐ HERE
)
end
In the method above you should explicitly list :linkedin_url:
def user_profile_params
params.require(:user).permit(
:phone_number,
user_profile_attributes: [:work_address, :work_zipcode, :linkedin_url]
)
end
Just solved my own problem, it was because i didn't whitelist :id in the strong parameters.
i have the active record reputation system working however i cant seem to hide the voting button once a user has voted for something.
in user.rb i have a voted for method
has_many :evaluations, class_name: "RSEvaluation", as: :source
def voted_for?(review)
evaluations.where(target_type: review.class, target_id: review.id).present?
end
then in a reviews show page i have the following code to hide the buttons if the 'if' statements evaluates to true
<% if User.find(session[:user_id]) &&
!User.find(session[:user_id]).voted_for(#review)%>
<h3> Vote:
<%= link_to "Up", vote_review_path(#review, type: "up"), method: "post" %>
||
<%= link_to "Down", vote_review_path(#review, type: "down"), method: "post" %></h3>
<% end %>
The buttons still show up regardless. I've been following railscast and in that video they used current_user however i've user the User.find(session[:user_id]) to identify the user (current_user isn't defined and i always get the error "*undefined local variable or method `current_user'*"
Add to your application_helper.rb:
def current_user
#current_user ||= User.find(session[:user_id])
end
def logged_in?
!!current_user
end
Now you can use current_user and logged_in? in your views.
<% if logged_in? && !current_user.voted_for?(#review)%>
<h3> Vote:
<%= link_to "Up", vote_review_path(#review, type: "up"), method: "post" %>
||
<%= link_to "Down", vote_review_path(#review, type: "down"), method: "post" %></h3>
<% end %>
def voted_for?(review)
evaluations.where(target_type: review.class, target_id: review.id).count > 0
end
if your Review class has
has_reputation :votes, source: :user, aggregated_by: :sum
you can get all evaluations(reputation records) with
object.evaluations
So to determine whether there was some votes, by particular user you may use
class Review
def was_vouted_by? user
self.evaluations.find_by_source_id(user.id)
end
end
find_by_source_id - will return record which ruby evaluates to true, or nil which ruby evaluates to false
If post.published?
.post
/ Post stuff
Otherwise
.post.gray
/ Post stuff
I've implemented this with rails helper and it seems ugly.
= content_tag :div, :class => "post" + (" gray" unless post.published?).to_s do
/ Post stuff
Second variant:
= content_tag :div, :class => "post" + (post.published? ? "" : " gray") do
/ Post stuff
Is there a more simple and haml-specific way?
UPD. Haml-specific, but still not simple:
%div{:class => "post" + (" gray" unless post.published?).to_s}
/ Post stuff
.post{:class => ("gray" unless post.published?)}
- classes = ["post", ("gray" unless post.published?)]
= content_tag :div, class: classes do
/Post stuff
def post_tag post, &block
classes = ["post", ("gray" unless post.published?)]
content_tag :div, class: classes, &block
end
= post_tag post
/Post stuff
Really the best thing is to put it into a helper.
%div{ :class => published_class(post) }
#some_helper.rb
def published_class(post)
"post #{post.published? ? '' : 'gray'}"
end
HAML has a nice built in way to handle this:
.post{class: [!post.published? && "gray"] }
The way that this works is that the conditional gets evaluated and if true, the string gets included in the classes, if not it won't be included.
Updated Ruby syntax:
.post{class: ("gray" unless post.published?)}