I have nested routes as follows;
resources :boats, except: :destroy do
resources :pictures
end
So user can upload picture and everything works fine. But picture/index.html.erb. I can not see all the pictures. It returns nil. But I can see pictures in the database. Probably because I try to retrieve wrong parameter.
When I take out the if statement <% if #pictures.present? %> it throws and error;
NoMethodError in PicturesController#create
undefined method `each' for nil:NilClass
<% #pictures.each do |pic| %>
Here is #index view;
<div class="container">
<h1>Pictures#index!</h1>
<p>Find me in app/views/pictures/index.html.erb</p>
<% if #pictures.present? %> <!-- Returns nil-->
<% #pictures.each do |pic| %>
</br>
<%= pic.name %>
<%= image_tag pic.image_url(:thumb).to_s %>
<%= link_to "edit", edit_boat_picture_path(#boat, #picture) %> |
<td><%= link_to 'Destroy', [#boat, #picture], confirm: 'Are you sure?', method: :delete %></td> |
</br>
<% end %>
<% end %>
<%= link_to "edit", edit_boat_picture_path(#boat, #picture) %> |
</br>
</br>
<%= link_to "add", new_boat_picture_path(#boat, #picture) %>
</div>
So here, picture.present returns always nil, so I can not display any images.
Here is pictures controller;
class PicturesController < ApplicationController
before_action :logged_in_user
before_filter :load_parent
def index
#pictures = #boat.pictures.all
end
def new
#picture = #boat.pictures.new
end
def show
#picture = #boat.pictures.find(params[:id])
end
def create
#picture = #boat.pictures.new(picture_params)
if #picture.save
#flash[:success] = "Continue from here"
render 'index'
#redirect_to boat_path(#boat)
else
render 'new'
end
end
def edit
#picture = Picture.find(params[:id])
end
def update
#picture = #boat.pictures.find(params[:id])
if #picture.update_attributes(picture_params)
flash[:notice] = "Successfully updated picture."
render 'index'
else
render 'edit'
end
end
def destroy
#picture = #boat.pictures.find(params[:id])
#picture.destroy
flash[:notice] = "Successfully destroyed picture."
redirect_to boat_path(#boat)
end
private
def picture_params
params.require(:picture).permit(:name, :image)
end
def load_parent
#boat = Boat.find(params[:boat_id])
end
end
EDIT 1:
Log;
{"utf8"=>"✓", "authenticity_token"=>"i3FW1zbhoGW2vavipN9NJ2Fvi9R1Lk/CKDsAttuqHWb8rFNmJgXpjE2D25oAqJ3xp9BXAnd0kDmrdIxhn1Qrpw==", "picture"=>{"name"=>"", "image"=>#<ActionDispatch::Http::UploadedFile:0x007fb4a5f50f30 #tempfile=#<Tempfile:/var/folders/w0/703ccggs56l3hrc79h3rdylm0000gn/T/RackMultipart20150423-5028-1rbpgnj.jpg>, #original_filename="imgres-4.jpg", #content_type="image/jpeg", #headers="Content-Disposition: form-data; name=\"picture[image]\"; filename=\"imgres-4.jpg\"\r\nContent-Type: image/jpeg\r\n">}, "commit"=>"Done", "controller"=>"pictures", "action"=>"create", "boat_id"=>"114"}
EDIT 2:
if I add #pictures = #boat.pictures.all to create that is fine, but all pics have its own destroy button.And when I look at them all shows the same address, so clicking to destroy, destroys all of them;
All of the destroy ids are the same. I though index action lists all and destroy erases individually. This case is same for edit action too
EDIT 3:
#boats controller
class BoatsController < ApplicationController
before_action :logged_in_user, only: [:new, :show, :edit, :update]
def new
#boat = Boat.new
end
def create
#boat = current_user.boats.new(boat_params) if logged_in?
if #boat.save
#flash[:success] = "Continue from here"
render 'edit'
else
render 'new'
end
end
def show
#boat = Boat.find(params[:id])
end
def edit
#boat = Boat.find(params[:id])
end
def update
#boat = Boat.find(params[:id])
if #boat.update_attributes(boat_params)
flash[:success] = "The Boat Saved"
redirect_to root_path
else
render 'edit'
end
end
def update_years
# updates year and model based on brand selected
brand = Brand.find_by_name(params[:brand_name])
# map to name and id for use in our options_for_select
#years = brand.years.map{|a| [a.name, a.name]}.insert(0, "Select a Year") #use a.name here instead of a.id
#models = brand.models.map{|s| [s.name, s.name]}.insert(0, "Select a Model")#use s.name here instead of s.id
end
def update_models
# updates model based on year selected
year = Year.find_by_name(params[:year_name])
#models = year.models.map{|s| [s.name, s.name]}.insert(0, "Select a Model") #use s.name here instead of s.id
end
private
def boat_params
params.require(:boat).permit(:brand, :year, :model, :captained, :boat_type, :daily_price, :boat_length, :listing_tagline, :listing_description, :boat_category, :hull_material, :mast_material)
end
end
There is no #pictures in your create action.
You can try:
def create
#picture = #boat.pictures.new(picture_params)
if #picture.save
#flash[:success] = "Continue from here"
#pictures = #boat.pictures.all
render 'index'
#redirect_to boat_path(#boat)
else
render 'new'
end
end
For buttons:
<% #pictures.each do |pic| %>
</br>
<%= pic.name %>
<%= image_tag pic.image_url(:thumb).to_s %>
<%= link_to "edit", edit_boat_picture_path(#boat, pic) %> |
<td><%= link_to 'Destroy', boat_picture_path(#boat, pic), confirm: 'Are you sure?', method: :delete %></td> |
</br>
<% end %>
Related
I'm using acts_as_voteable for upvote/downvote on a tweets page which works fine. however it reloads the page when i do this which i want to avoid
<% #tweets.each do |tweet| %>
<div class="card">
<div class="card-description">
<h4><%= link_to tweet.user.username, user_path(tweet.user) %></h4>
<p class="tweet-content"><%= tweet.content %></p>
<p><%= tweet.created_at.strftime("%B %d %Y, %l:%M%P") %></p>
<%= link_to like_tweet_path(tweet), method: :put do %>
<p>Upvote <%= tweet.get_upvotes.size %>
<% end %>
<%= link_to dislike_tweet_path(tweet), method: :put do %>
Downvote <%= tweet.get_downvotes.size %></p>
<% end %>
</div>
</div>
<% end %>
class TweetsController < ApplicationController
before_action :authenticate_user!, :except => [:index]
def index
# #tweets = Tweet.all.order("created_at DESC")
#tweets = Tweet.paginate(page: params[:page], per_page: 7).order('created_at DESC')
#tweet = Tweet.new
#user = current_user
end
def show
#tweet = Tweet.find(params[:id])
end
def new
# #tweet = Tweet.new
end
def create
# #user = current_user
#user = User.find(params[:user_id])
#tweet = Tweet.new(tweet_params)
#tweet.user = #user
if #tweet.save
redirect_to user_tweets_path
end
end
def edit
#tweet = Tweet.find(params[:id])
end
def update
#tweet = Tweet.find(params[:id])
#tweet.update(tweet_params)
redirect_to tweets_path
end
def upvote
#tweet = Tweet.find(params[:id])
#tweet.upvote_by current_user
# redirect_to :tweets
if request.xhr?
head :ok
else
redirect_to tweets_path
end
end
def downvote
#tweet = Tweet.find(params[:id])
#tweet.downvote_by current_user
redirect_to :tweets
end
private
def tweet_params
params.require(:tweet).permit(:content)
end
end
You can use remote: true in the link_to tag.
For example:
You have <%= link_to like_tweet_path(tweet), method: :put do %>
You can have it this way <%= link_to like_tweet_path(tweet), method: :put, remote: true do %>
Then just handle the request with format.js
I wanna fetch feature index page without going through grounddetail id. When i try to create a link in homepage i always get this error:
No route matches {:action=>"index", :controller=>"features", :grounddetail_id=>nil} missing required keys: [:grounddetail_id]
<%= link_to "Account Setting", edit_admin_registration_path %> |
<%= link_to "Log Out", destroy_admin_session_path, method: :delete %> |
<%= link_to "Featured Ground", grounddetail_features_path(#grounddetail) %> # Feature Link Where I get error
grounddetail controller looks :
class GrounddetailsController < ApplicationController
before_action :find_ground, only: [:show, :edit, :destroy, :update]
def index
#grounddetails = Grounddetail.all.order('created_at DESC')
#grounddetail = Grounddetail.first # With this code it run but with grounddetail id.
end
def new
#grounddetail = Grounddetail.new
end
def edit
end
def show
end
def create
#grounddetail = Grounddetail.new(ground_params)
if #grounddetail.save
redirect_to #grounddetail
else
render 'new'
end
end
def update
if #grounddetail.update(ground_params)
redirect_to #grounddetail
else
render 'edit'
end
end
def destroy
#grounddetail.destroy
redirect_to root_path
end
private
def find_ground
#grounddetail = Grounddetail.find(params[:id])
end
def ground_params
params.require(:grounddetail).permit(:name, :working_hours, :end_time, :address, :contact_no, :email, :number_of_grounds, :description, :featured_ground)
end
end
feature controller looks like :
class FeaturesController < ApplicationController
before_action :set_ground
def index
#grounddetails = Grounddetail.where(featured_ground: true).order("created_at DESC")
#features = Feature.includes(:grounddetail).where(grounddetail_id: #grounddetail.id)
end
def new
#feature = Feature.new
end
def show
#feature = Feature.find(params[:id])
end
def edit
#feature = Feature.find(params[:id])
end
def create
#feature = Feature.create(feature_params)
#feature.grounddetail_id = #grounddetail.id
if #feature.save
redirect_to grounddetail_features_path(#grounddetail)
else
render 'new'
end
end
def update
#feature = Feature.find(params[:id])
if #feature.update(feature_params)
redirect_to grounddetail_features_path(#grounddetail)
else
render 'edit'
end
end
def destroy
#feature = Feature.find(params[:id])
#feature.destroy
redirect_to grounddetail_features_path(#grounddetail)
end
private
def set_ground
#grounddetail = Grounddetail.find(params[:grounddetail_id])
end
def feature_params
params.require(:feature).permit(:featuring_start_time, :featuring_end_at)
end
end
Models:
grounddetail model:
has_many :features
feature model:
belongs_to :grounddetail
index.html.erb #feature index page
<h2>Featured Ground</h2>
<% #grounddetails.each do |grounddetail| %>
Name: <%= link_to grounddetail.name, grounddetail %><br>
Address: <%= grounddetail.address %><br>
Opening Hours: From<%= grounddetail.working_hours.strftime("%l:%M %P") %> To <%= grounddetail.end_time.strftime("%l:%M %P") %><br>
Featured : <%= check_box "Grounddetail", "Featured Ground", {checked: grounddetail.featured_ground, disabled: true} %><br>
<% if (grounddetail.featured_ground = true) && (grounddetail_id = #grounddetail.id) %>
<% #features.each do |feature| %>
Featuring Start Time : <%= feature.featuring_start_time.strftime('%e %b %Y %l:%M %P') %><br>
<%# feature.start_date_cannot_be_in_the_past %>
Featuring End At : <%= feature.featuring_end_at.strftime('%e %b %Y %l:%M %P') %><br>
<% end %>
<% end %>
<%= link_to "Add Featuring Time", new_grounddetail_feature_path(#grounddetail) %><br><br>
<% end %>
routes.rb
resources :grounddetails do
resources :features
end
Sorry for the mess up..
The error output is:
NoMethodError in MembersController#index
undefined method `total_pages' for #<Micropost::ActiveRecord_Associations_CollectionProxy:0x007ffc26104288>
Application trace is:
app/views/shared/_feed.html.erb:5:in `_app_views_shared__feed_html_erb__933429040368905157_70360748756160'
app/views/members/index.html.erb:4:in `_app_views_members_index_html_erb__2919315027143638402_70360970104820'
Update:
Source near error:
arel.public_send(method, *args, &block)
else
super # marked red
end
end
end
Additional info:
app/views/members/index.html.erb renders two partials using another controller, microposts_controller. So I'll show contents of both controllers and of the two partials.
# app/views/members/index.html.erb
<%= render 'shared/micropost_form', :locals => { :micropost => #micropost } %>
<%= render 'shared/feed', :locals => { :feed_items => #feed_items } %>
MembersController
class MembersController < ApplicationController
def index
#micropost = current_user.microposts.build
#feed_items = current_user.microposts
end
end
micropost_controller.rb
# controllers/micropost_controller.rb
class MicropostsController < ApplicationController
before_action :logged_in_user, only: [:create, :destroy]
before_action :correct_user, only: :destroy
def create
#micropost = current_user.microposts.build(micropost_params)
if #micropost.save
flash[:success] = "Micropost created!"
redirect_to '/members'
else
#feed_items = []
render '/members'
end
end
def destroy
#micropost.destroy
flash[:success] = "Micropost deleted"
redirect_to request.referrer || '/members'
end
private
def micropost_params
params.require(:micropost).permit(:content, :picture)
end
def correct_user
#micropost = current_user.microposts.find_by(id: params[:id])
redirect_to '/members' if #micropost.nil?
end
end
_micropost_form.html.erb
# shared/_micropost_form.html.erb
<%= form_for(#micropost, html: { multipart: true }) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="field">
<%= f.text_area :content, placeholder: "Compose new micropost (420 chars max)..." %>
</div>
<%= f.submit "Post", class: "btn btn-primary" %>
<span class="picture">
<%= f.file_field :picture, accept: 'image/jpeg,image/gif,image/png' %>
</span>
<% end %>
<script type="text/javascript">
$('#micropost_picture').bind('change', function() {
size_in_megabytes = this.files[0].size/1024/1024;
if (size_in_megabytes > 5) {
alert('Maximum file size is 5MB. Please choose a smaller file.');
}
});
</script>
_feed.html.erb
# shared/_feed.html.erb
<% if #feed_items.any? %>
<ol class="microposts">
<%= render #feed_items %>
</ol>
<%= will_paginate #feed_items %>
<% end %>
You want to paginate your records using will_paginate in view, but you didn't paginate them in your controller:
def index
#micropost = current_user.microposts.build
#feed_items = current_user.feed.paginate(page: params[:page])
end
name
metric
date_value
result_value
None of the above attributes are showing when I load the index page.
I know its because of this line: <% if averaged.user == current_user %>
More specifically it's because of the nested attributes of date_value and result_value (because if I take out those nested attributes the name & metric will show)
What do I need to add to the controller to allow the nested attributes to show on the index page, and in effect all the attributes?
Thanks in advance for your service!
<div id="values" class="panel panel-default">
<div class="panel-heading"><h4><b>AVERAGE</b></h4></div>
<!-- Table -->
<table>
<% #averaged_quantifieds.each do |averaged| %>
<% if averaged.user == current_user %>
<th class="value">
<%= link_to edit_quantified_path(averaged) do %>
<%= averaged.name %>
<% end %>
(<%= averaged.metric %>)
</th>
<tbody class="value">
<td><%= averaged.date_value.strftime("%m-%Y") %></td>
<td><%= averaged.result_value %></td>
</tbody>
<% end %>
<% end %>
</table>
</div>
controller
class QuantifiedsController < ApplicationController
before_action :set_quantified, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!, except: [:index, :show]
def index
#averaged_quantifieds = current_user.quantifieds.averaged
#instance_quantifieds = current_user.quantifieds.instance
#averaged_quantifieds = Result.all.order("date_value")
#instance_quantifieds = Result.all.order("date_value")
end
def show
end
def new
#quantified = current_user.quantifieds.build
#quantified = Quantified.new
end
def edit
end
def create
#quantified = current_user.quantifieds.build(quantified_params)
if #quantified.save
redirect_to quantifieds_url, notice: 'Quantified was successfully created'
else
render action: 'new'
end
end
def update
if #quantified.update(quantified_params)
redirect_to quantifieds_url, notice: 'Goal was successfully updated'
else
render action: 'edit'
end
end
def destroy
#quantified.destroy
redirect_to quantifieds_url
end
private
def set_quantified
#quantified = Quantified.find(params[:id])
end
def correct_user
#quantified = current_user.quantifieds.find_by(id: params[:id])
redirect_to quantifieds_path, notice: "Not authorized to edit this goal" if #quantified.nil?
end
def quantified_params
params.require(:quantified).permit(:categories, :name, :metric, :result, :date, results_attributes: [:id, :result_value, :date_value, :_destroy])
end
end
quantified.rb
class Quantified < ActiveRecord::Base
belongs_to :user
scope :averaged, -> { where(categories: 'averaged') }
scope :instance, -> { where(categories: 'instance') }
has_many :results
accepts_nested_attributes_for :results, :reject_if => :all_blank, :allow_destroy => true
CATEGORIES = ['averaged', 'instance']
end
Please let me know if you need any more code or comments to help bring this question to a resolution.
This will hopefully guide you in the right direction
This is odd to me
def index
#averaged_quantifieds = current_user.quantifieds.averaged
#instance_quantifieds = current_user.quantifieds.instance
#averaged_quantifieds = Result.all.order("date_value")
#instance_quantifieds = Result.all.order("date_value")
end
You define both of these twice and essentially overwrite each other?
If your attributes aren't showing, it doesn't have anything to do with the nesting, it has to do with the logic. So in other words, this logic
if averaged.user == current_user
is not evaluating to true, so check what each object is actually holding. You can do this in a dirty way by just inspecting it in the view
e.g. put <%= averaged.user.inspect %> and <%= current_user.inspect %>
Once you know what objects it's holding, go backwards in your code to how you altered them to this state. I suspect it'll go back to the controller where you have some issues.
I am making a form in my rails application where people have the option of adding images and I am using 'carrierwave' but I am getting an undefined method error on the edit page. Here is the code for the form:
<%= title "Add Item to #{#todo_list.title}" %>
<%= form_for [#todo_list, #todo_item], builder: FoundationFormBuilder do |form| %>
<%= render partial: 'form', locals: { form: form } %>
<%= form.file_field :picture %>
<% end %>
Here I can see the upload button and it is working fine but on the edit page I get the above stated error. Code for my edit page:
<%= title "Editing Todo Item" %>
<%= form_for [#todo_list, #todo_item], builder: FoundationFormBuilder do |form| %>
<%= render partial: 'form', locals: { form: form } %>
<% end %>
<div class="row">
<div class="small-12 columns">
<%= link_to "Delete", todo_list_todo_item_path(#todo_list, #todo_item), method: :delete, data: { confirm: "Are you sure?" }, class: "button radius expand alert" %>
</div>
<%= #todo_item.picture %>
</div>
Why is this showing an undefined method error. I tried creating a method in my todo_item model but its still showing the above error.
Controller for todo_item:
class TodoItemsController < ApplicationController
before_action :require_user
before_action :find_todo_list
before_action :set_back_link, except: [:index]
def index
go_back_link_to todo_lists_path
end
def new
#todo_item = #todo_list.todo_items.new
end
def create
#todo_item = #todo_list.todo_items.new(todo_item_params)
if #todo_item.save
flash[:success] = "Added todo list item."
redirect_to todo_list_todo_items_path
else
flash[:error] = "There was a problem adding that todo list item."
render action: :new
end
end
def edit
#todo_item = #todo_list.todo_items.find(params[:id])
end
def update
#todo_item = #todo_list.todo_items.find(params[:id])
if #todo_item.update_attributes(todo_item_params)
flash[:success] = "Saved todo list item."
redirect_to todo_list_todo_items_path
else
flash[:error] = "That todo item could not be saved."
render action: :edit
end
end
def destroy
#todo_item = #todo_list.todo_items.find(params[:id])
if #todo_item.destroy
flash[:success] = "Todo list item was deleted."
else
flash[:error] = "Todo list item could not be deleted."
end
redirect_to todo_list_todo_items_path
end
def complete
#todo_item = #todo_list.todo_items.find(params[:id])
#todo_item.toggle_completion!
redirect_to todo_list_todo_items_path, notice: "Todo item updated."
end
def url_options
{ todo_list_id: params[:todo_list_id] }.merge(super)
end
private
def set_back_link
go_back_link_to todo_list_todo_items_path(#todo_list)
end
def find_todo_list
#todo_list = current_user.todo_lists.find(params[:todo_list_id])
end
def todo_item_params
params[:todo_item].permit(:content)
end
end
To display your image you should change
<%= #todo_item.picture %>
to
<%= image_tag(#todo_item.picture_url) %>