I've started moving all my view logic to presenters and I'm getting the following error NameError at /bids
uninitialized constant Bid::ActiveRecord_Associations_CollectionProxyPresenter on my index view. The presenter works in all my other views for this model except index. I've added commented code of fixes I've tried.
Code:
Index view:
<% present #bids do |bid_presenter| %>
<% end %>
# tried #bids to match controller
# <% present #bids do |bid_presenter| %>
# <% end %>
bid_presenter.rb:
class BidPresenter < BasePresenter
presents :bid
# tried :bids
# presents :bids
end
base_presenter.rb:
class BasePresenter
def initialize(object, template)
#object = object
#template = template
end
private
def self.presents(name)
define_method(name) do
#object
end
end
# h method returns the template object
def h
#template
end
def method_missing(*args, &block)
#template.send(*args, &block)
end
end
bids_controller.rb:
def index
#bids = current_user.bids
end
Have you tried:
<% #bids.each do |bid| %>
<% present bid do |bid_presenter| %>
<% end %>
<% end %>
The Presenter is presenting an instance of the model; your code is trying to present an ActiveRecord::Collection or something.
Related
I have to show data from this website: https://baconipsum.com/json-api/ , but I don't know where to write the code of it in my app. What code do I have to write for controllers and in views?
Setup faraday:
bacon = Faraday.new("https://baconipsum.com/") do |f|
f.response :json # automatically parse responses as json
end
Send a request in the controller:
#bacon = bacon.get("api/", type: 'all-meat', sentences: 1).body # => ["Leberkas frankfurter chicken tongue."]
Use it in the view:
<% #bacon.each do |meat| %>
<p>
<%= meat %>
</p>
<% end %>
https://lostisland.github.io/faraday/usage/
Update
There are many ways to set it up. Very simple set up could look like this:
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
private
# NOTE: this method will be accessible in any controller
# that inherits from ApplicationController
def baconipsum
# NOTE: memoize for a bit of performance, in case you're
# making multiple calls to this method.
#baconipsum ||= Faraday.new("https://baconipsum.com/") do |f|
f.response :json
end
end
end
# app/controllers/articles_controller.rb
class ArticlesController < ApplicationController
def show
#article = Article.find(params[:id])
# I'm not quite sure what you're trying to do with it;
# change this to fit your use case.
#bacon = baconipsum.get("api/", type: 'all-meat').body
end
end
# app/views/articles/show.html.erb
<% #bacon.each do |meat| %>
<p> <%= meat %> </p>
<% end %>
I am trying display the task related to logged in user but on my html page nothing show except the tag data
task_controller.rb
class TaskController < ApplicationController
def all_task
if current_user.present?
#all_task = Task.find_by_user_id(#current_user.id)
render template: 'task/allTask'
end
end
end
routes.rb
get 'all_task' => 'task#all_task'
task.erb
<p>All Task</p>
<% if user_signed_in? %>
<%#all_task.daily_task %>
<%#all_task.date %>
<%#all_task.created_at %>
<%end %>
Start by setting up an assocation between users and tasks:
class User < ApplicationRecord
# ...
has_many :tasks
end
Then setup the route and controller:
get '/user/tasks', to: 'users/tasks#index', as: :user_tasks
# app/controllers/users/tasks_controller.rb
module Users
class TasksController < ApplicationRecord
before_action :authenticate_user!
# display all the tasks belonging to the currently signed in user
# GET /user/tasks
def index
#tasks = current_user.tasks
end
private
# You don't need this if your using Devise
def authenticate_user!
unless current_user
redirect_to '/path/to/your/login',
notice: 'Please sign in before continuing'
end
end
end
end
Note that when you have a route like this that displays resources that belong to the current user you should use a callback to bail early and redirect the user to sign in instead of using if current_user.present? and giving a response which is meaningless to the user. This code should be DRY:ed into your ApplicationController (even better yet is to not reinvent the auth wheel).
You can link to the users tasks with:
<% if current_user.present? %>
<%= link_to 'My tasks', user_tasks_path %>
<% end %>
In your view you need to iterate across the returned tasks:
# app/views/users/tasks/index.html.erb
<p>All Tasks</p>
<% if #tasks.any? %>
<% #tasks.each do |task| %>
<%= task.daily_task %>
<%= task.date %>
<%= task.created_at %>
<% end %>
<% else %>
<p>You don't have any tasks.</p>
<% end %>
You can cut duplication here by using partials.
Can you make sure if the instance variable #current_user is defined? If not, try the following:
class TaskController < ApplicationController
def all_task
if current_user.present?
#all_task = Task.find_by_user_id(current_user.id)
render template: 'task/allTask'
end
end
end
instead of
class TaskController < ApplicationController
def all_task
if current_user.present?
#all_task = Task.find_by_user_id(#current_user.id)
render template: 'task/allTask'
end
end
end
I'm building my photography portfolio in Rails 4.1.6 and Ruby 2.0.0p576.
I have 'collections' which have many 'photos'.
I am using dragonfly 1.0.10 for image uploads.
Collections Model
class Collection < ActiveRecord::Base
belongs_to :admin
has_many :photos
end
Photos Model
class Photo < ActiveRecord::Base
belongs_to :collection
extend Dragonfly::Model
dragonfly_accessor :image
end
Collection Controller
class CollectionsController < ApplicationController
respond_to :html, :xml, :json
def index
#collections = Collection.all
end
def new
#collection = Collection.new
respond_with (#collection)
end
def create
#collection = Collection.new(collection_params)
#collection.save
respond_with (#collection)
end
def edit
#collection = Collection.find(params[:id])
end
def update
#collection = Collection.find(params[:id])
if #collection.update(collection_params)
redirect_to #collection
else
render 'edit'
end
end
def show
#collection = Collection.find(params[:id])
end
def destroy
#collection = Collection.find(params[:id])
#collection.destroy
respond_with (#collection)
end
private
def collection_params
params.require(:collection).permit(:name, :desc, photos: [:image] )
end
end
Photos Controller
class PhotosController < ApplicationController
def new
#collection = Collection.find(params[:id])
#photo = #collection.new
end
def create
#collection = Collection.find(params[:collection_id])
#photo = #collection.photos.create(photo_params)
redirect_to collection_path(#collection)
end
private
def photo_params
params.require(:photo).permit(:image)
end
end
This is storing my photos for me correctly.
But on my collection show page, I'm getting a "NoMethodError in Collections#show undefined method `image'.
In terminal, I get the following error:
ActionView::Template::Error (undefined method `image' for #):
Code for the show page is below:
collections/show.html.erb
<h1><%= #collection.name %></h1>
<p><%= #collection.desc %></p>
<% #collection.photos.each do |photo| %>
<div>
<%= image_tag #collection.photos.image.thumb('400x300#').url %>
</div>
<% end %>
I'm an absolute rails n00b and need some help as to how to fix this and be able to view all the photos of the collection on its show page.
Please help!
You have a wrong usage of the each loop:
<% #collection.photos.each do |photo| %>
<div>
<%= image_tag photo.image.thumb('400x300#').url %>
</div>
<% end %>
Read How does iteration work in Ruby?
I am new at RoR, I have been searching and searching but can't seem to find a solution. I have a simple form:
<%= form_for #case do |f| %>
<%= f.select( :case, options_for_select([['CASE1','CASE1'],['CASE2','CASE2'],['CASE3','CASE3'],['CASE4','CASE4']])) %>
<% end %>
That is in my nav bar. It is not based on any table in the DB.
Controller:
class MyAppController < ApplicationController
before_filter :initialize_remote_user
def self.search(name)
#results = MyApp.search(params[:name])
#case = params[:case]
end
def result
#results = MyApp.where("name = ?",params[:name]).order("item_scan_date ASC")
puts #results.inspect
end
def update
end
def change
end
def show
#case = params[:case].inspect
end
def create
end
def new
end
def index
end
private
def name_params
params.require(:name).permit(:name)
end
def case_params
params.require(:case).permit(:case, :id)
end
When I have #case = params[:case].inspect it doesn't have any errors, but it doesn't pull the data from the <%= form_for #case do |f| %>
I have tried
def show
#case = Case.find(params[:case])
end
but end up with NameError uninitialized constant MyAppController::Case error at #case = Case.find(params[:case])
I can't seem to get #case to pull up anything but nil
If I have #case = params[:case] in def show I get 'ArgumentError First argument in form cannot contain nil or be empty error at <%= form_for #case do |f| %>
Try simple_form for your forms see: https://github.com/plataformatec/simple_form and read the documentation under Collections to handle input for :case
Also make sure your create and new methods aren't empty, or else your form won't save.
Hope it helps.
I have an instance variable #posts_by_month defined in two controllers and is used in two views:
Posts controller:
class PostsController < ApplicationController
def index
#posts = Post.all
#posts_by_month = Post.all.group_by { |post| post.created_at.strftime("%L") }
respond_to do |format|
format.html # index.html.erb
format.json { render json: #posts }
end
end
.
.
end
Archives controller:
class ArchivesController < ApplicationController
def index
#posts_by_month = Post.all.group_by { |post| post.created_at.strftime("%B") }
end
end
Posts index view:
<h1>Listing posts</h1>
.
.
.
<div>
<% #posts_by_month.each do |millisecond, posts| %>
<p><%= millisecond %>milliseconds <%= posts.count %></p>
<% end %>
</div>
Archives index view:
<% #posts_by_month.each do |monthname, posts| %>
<%= monthname %>
<ul>
<% posts.each do |post| %>
<h3><%= post.title %></h3>
<p><%= post.body %></p>
<% end %>
</ul>
<% end %>
I have two questions. Is there any way I can define the #posts_by_month instance variable so that I can have it available to both views without repeating it in each respective controller?
Secondly, is there any way that the millisecond part of <p><%= millisecond %>milliseconds <%= posts.count %></p> can be made into a link that leads to the archive view?
Note: In my app millisecond will be replaced by month as in the archive view.
When an action was executed, aka rendered, the instance is over. There is no more instance variable.
The instance variables in View are not real instance variables. View and Controller are in different classes, how can they share instance? The reality is, what Rails does is to copy those instance variable from Controller instance to View instance exactly.
So the answer in your question is: No.
But you can still dry your code by a private method in application controller, to share with PostsController and ArchiveController.
class ApplicationController
private
def posts_by_time(arg)
Post.all.group_by { |post| post.created_at.strftime(arg) }
end
end
class PostsController < ApplicationController
def index
#posts = posts_by_time "%L"
# ...
end
end
class ArchievesController < ApplicationController
def index
#posts = posts_by_time "%B"
# ...
end
end
Yes you can reduce duplicacy of same variable. One way is to use filters:
Define a mthod inside application controllers:
class ApplicationController < ActionController::Base
private
def find_post_by_month
#posts_by_month = Post.all.group_by { |post| post.created_at.strftime("%L") }
end
end
Then inside archive and posts controllers:
class ArchivesController < ApplicationController
before_filter :find_post_by_month, :only => :index
...
end
class PostsController < ApplicationController
before_filter :find_post_by_month, :only => :index
...
end
This will give you value in #posts_by_month variable.
And, for making link of mentioned text, you should use this code:
<p><%= link_to "#{millisecond} milliseconds", path %></p> # Replace path with your url