url_for in an email sent by a rake task in rails 4 - ruby-on-rails-4

I have a rake task that sends out daily digest emails of player activity during a day. (See example code below.) If I run PlayerActivityMailer.activity_report.deliver in my console, everything works just fine. However, when I try to invoke the rake task, I get the following error:
rake aborted!
ActionView::Template::Error: arguments passed to url_for can't be handled.
Please require routes or provide your own implementation
After doing some research, I found that in Rails 4, they totally nerfed ActionView::Helpers::UrlHelper.url_for (http://apidock.com/rails/v4.1.8/ActionView/Helpers/UrlHelper/url_for - notice the giant red minus sign under the 4.0.2). If you look at the source, you can see the error I'm seeing - it no longer takes options. As far as I can tell, that functionality still exists in other url_fors, such as the one in ActionDispatch::Routing::UrlFor. Also, the error message suggests including Rails.application.routes.url_helpers.
What I've tried
include ActionDispatch::Routing::UrlFor in both the rake task (inside the task) and the mailer (both at the same time, and each separately)
include Rails.application.routes.url_helpers in the same places and configurations, both with and without the UrlFor include.
The error still persists. My guess is that the page view is still insisting on using the ActionView::Helpers::UrlHelper version of url_for. I don't think I can include things actually in the views (which is sloppy looking and hacky even if I could).
Example Code
(heavily sanitized)
config/environtments/development.rb:
config.action_mailer.default_url_options = { host: 'localhost:3000' }
lib/tasks/player.rake:
namespace :player do
task :activity => :environment do
PlayerActivityMailer.activity_report.deliver
end
end
app/mailers/player_activity_mailer.rb:
class PlayerActivityMailer < ActionMailer::Base
def activity_report
#activities = PlayerActivity.all
mail(to: 'foo#bar.com', subject: 'activity report')
end
end
app/views/player_activity_mailer/activity_report.html.erb:
<% #activites.each do |activity| %>
Player: <%= link_to activity.player.name, player_url(id: activity.player.id) %>
...
<% end %>
I also have a model Player, resources :players in my routes.rb file, and a PlayerActivity class with an association to Player.
I'm currently using the (really horrifying) workaround of #base_url = Rails.configuration.action_mailer.default_url_options[:host] in my mailer action and "http://#{#base_url}/players/#{activity.player.id}" in my view instead of the player_url part.
Help!

Have you tried passing just your player in the URL? Like this:
<% #activites.each do |activity| %>
Player: <%= link_to activity.player.name, player_url(activity.player) %>
<% end %>

Related

Getting same style in another page when click to login

I am having a login page for user generated by devise gem.where I removed the registerable from model for only login not for signup.I have also generated an admin which gives default login credentials for user in seed.rb file.I have done some css work in login page. next I have generated an employee page for further process for users.
Here my doubt is the styling part what I have done in login page is also coming in employee page. I dont want that so I wrote some condition in application.html.erb
<% unless user_signed_in? %>
<%= render 'layouts/heading' %>
<% end %>
The method is defined in application.controller.rb
def user_signed_in? %>
render :layouts => 'application'
end
I tried a lot by changing conditions but it is still displaying or showing errors.
You said that you're using "device gem", but since you're talking about authentication, I assume you mean "devise"?
The user_signed_in? method is a helper which should be provided automatically by devise, and you should be able to use it in your views. You shouldn't need to define it in the application controller.
You probably want to make sure you do "before_filter :authenticate_user!" in the relevant controller (you can use the ":only" option if you only want this to apply for certain methods).
It's difficult to give any more information because you haven't said what errors you are getting. I assume you're getting some kind of syntax error on the definition of the "user_signed_in?" method, since you have an invalid "%>"on the end of the line, which I guess you copied-and-pasted from an ERB file.

Rails 4 Fragment Cache Entire Page. How to Expire Cache In Model

How do I expire the main-page fragment in a model?
In my HTML
<% cache 'main-page' do %>
# html here
<% end %>
In my Post Model
after_create :clear_cache
after_update :clear_cache
def clear_cache
ActionController::Base.new.expire_fragment('main-page')
end
This doesn't clear the cache. If I create or update a post, the cache doesn't clear. If I run ActionController::Base.new.expire_fragment('main-page') in rails console it returns 'nil'. If I run Rails.cache.clear instead of ActionController::Base.new.expire_fragment('main-page') in the post model, it works.
I believe your issue is the digest, so if you change your cache to this it should work:
<% cache 'main-page', skip_digest: true do %>
# html here
<% end %>
If you want to use this kind of style, where the cache doesn't expire and relies on detecting model changes to invalidate, you may want to consider using an Observer or Sweeper, which were removed from Rails 4, but are useful for this pattern:
https://github.com/rails/rails-observers
Not the answer you are looking for perhaps, but another way:
Make the cache key based on the max updated_at from the Post model.
Whenever any post changes, the cache key will automatically miss and go retrieve the latest posts to re-cache that part of the view.
module HomeHelper
def cache_key_for_posts
count = Post.count
max_updated_at = Post.maximum(:updated_at).try(:utc).try(:to_s, :number)
"posts/all-#{count}-#{max_updated_at}"
end
end
And then in your view:
<% cache cache_key_for_posts, skip_digest: true do %>
# html here
<% end %>

Can't get sabisu gem to render - shows no input found for inet error

so i'm working through the api on rails tutorial - http://apionrails.icalialabs.com/book - and i keep getting the error 'no input found for inet' in my error window.
the error highlights this block of code as where the issue is occuring:
<div class="appeareable">
<% #explorer.resource_columns.each do |column| %>
<%= f.input column, input_html: {name: "#{#explorer.resource_name}[#{column}]" }, as: #explorer.column_type(column), required: #explorer.required_attribute?(column) %>
<% end %>
</div>
I tried locking out the compass and simple_form gems, but there are dependencies that start to fall apart using rails 4.1.4 and ruby 2.1.5.
it looks like simple_form is trying to render a resource named 'inet', but i can't find that anywhere in the gem code or even referenced anywhere on google.
It turns out that simple_form has a problem handling the 'inet' datatype now included in rails 4 by default for postgres - https://blog.engineyard.com/2013/new-in-rails-4 (ctrl-f for inet).
IPs used to be string datatype (varchar 255 in postgres) and so converting the db to string for the 2 IP fields in the user table (current_sign_in_ip and last_sign_in_ip) resolves this issue.
I would imagine simple_form will be updating to handle this new datatype at somepoint...though I didn't see any mention of it in their issue logs.
I did this by adding a new migration:
rails g migration change_ip_columns_in_users_table
Then I edited the migration file:
class ChangeIpColumnsInUsersTable < ActiveRecord::Migration
def change
change_column :users, :current_sign_in_ip, :string
change_column :users, :last_sign_in_ip, :string
end
end
The migration solved the problem.

dots in rails URL

I'm trying to add a show page to my devise users but can't seem to get the id value passed properly, how do I create a link to the show page? For some reason rails is doing this to URL
/show.1
users controller:
def show
#user = User.find(params[:id])
end
user/show.html.erb
<h1><%= #user.username %></h1>
link to user profile also gives me issues id no method
<%= link_to #post.email, users_show_path(#user.id) %>
routes.rb
get "users/show"
get "pages/faq"
get "pages/about"
devise_for :users
resources :posts
You have defined the show route as:
get "users/show"
Notice that there is no dynamic segment in this route, like :id. That means your route is not expecting any value to be passed. BUT while linking to this route you passed #user.id
<%= link_to #post.email, users_show_path(#user.id) %>
which the route was not expecting. So, Rails assumed that you are passing the format (like .html, .json, etc.) which is why you see the url formed as users/show.1.
To fix this, I would suggest you to add a dynamic segment to your route to capture the id of a user correctly.
Change
get "users/show"
With
get "users/show/:id" => "users#show", as: :users_show
For a user with id = 1, when you click on the user profile link the url generated would be http://yourdomain/users/show/1

How to use activemodel to validates date_time_select

I am using rails 4.0
I wonder how to validate date_select with activemodel
let's suppose I have the code as follow
app/models/book.rb
class Book
include ActiveModel::Model
include ActiveModel::Validations
attr_accessor :title, :written_on
validates :title, presence: true, allow_blank: false
# How validates :written_on if I use date_select Please look in my view below
end
app/controllers/books.rb
class BooksController < ApplicationController
#...
def new
#book = Book.new
end
def create
#book = Book.new(book_params)
if #book.valid?
#Do something
end
end
#...
end
app/views/books/new.html.erb
<% form_for #book do |f| %>
...
<%= f.date_select :written_on %>
...
<% end %>
I have also try adding
attr_accessor 'written_on(1i)'
to my book model but I got the error invalid attribute name 'written_on(1i)'
Really appreciated for the help here.
Just to clarify, I think you're asking why you're not even able to set the written_on attribute, let alone validate it-- when I used your exact code locally and tried to create a new book, on submit I got undefined method `written_on(1i)=' for Book.
This is because the Book model isn't inheriting from ActiveRecord::Base; you're just including ActiveModel::Model and ActiveModel::Validations. The Rails guide on form helpers says "when Active Record sees parameters with such names it knows they must be combined with the other parameters and given to a constructor appropriate to the column type."
So I started looking through the Rails source to see where this functionality was implemented, and it's currently in ActiveRecord::AttributeAssignment. There is currently an open pull request that moves this functionality to ActiveModel so that in cases like yours, you'd be able to use it by including ActiveModel::AttributeAssignment.
I'm not sure what you can do until that gets merged in and released. I tried including ActiveRecord::AttributeAssignment and still got the same error, and looking at the pull request, it doesn't seem to be that straightforward. You could fork Rails and apply that pull request, but you'd have to maintain your own Rails for a while until that lands, then get back on a released version.