If you take a look at the project here: http://www.leapfm.com/ you can scroll down and click More on the front page and it works. However, if you try doing that in New Songs tab it stays at 'Page is loading...'. I'm not quite sure why this is.
new_songs.html.erb
<div id="new_songs">
<%= render 'new_songs'%>
</div></div>
_new_songs.html.erb (partial)
<div id="layout-1">
<!--div class="left-side"> -->
<%#= will_paginate #songs %>
<h6>New songs</h6>
<hr>
<ol><% #songs.each do |song| %>
<span class="title">
<li><%= link_to song.title, song %><span class="subtext"> (<%= song.url %>)<br></li></span>
<%#=link_to '▼'.html_safe, vote_against_song_path(song), :remote => true, :method => :put %>
posted <%= time_ago_in_words(song.created_at) + " ago" %>
<small><span class="comments"></small> | <%= pluralize(song.comments.size, 'comment') %></span></small><br /></span>
<%#= link_to 'Show', song, class: "button small secondary" %>
<%= link_to('Edit', edit_song_path(song), class: "button small secondary") if can? :update, song %>
<%= link_to('Destroy', song, method: :delete, data: {confirm: 'Are you sure?'}, class: "button small secondary") if can? :destroy, song %>
<% end %>
</ol>
</div>
<div class="pagination-centered">
<ul class="pagination">
<%#= will_paginate #songs %>
<!-- or custom pagination -->
<% if #songs.previous_page %>
<%= link_to "Back", params.merge(page: #songs.previous_page) %>
<% end %>
<% if #songs.next_page %>
<%= link_to "More", params.merge(page: #songs.next_page) %>
<% end %>
</ul></div>
pagination.js
$(function() {
$(".pagination a").on("click", function() {
$(".pagination").html("Page is loading...");
$.getScript(this.href);
return false;
});
});
song_controller.rb
class SongsController < ApplicationController
before_filter :authenticate_user!, only: [:create ,:edit, :update, :destroy, :vote_for_song]
before_action :set_song, only: [:show, :edit, :update, :destroy, :vote_for_song]
def extract_video
#song = Song.find(params[:id])
#song.YouTubeAddy.extract_video_id
end
def vote_for
#song = Song.find(params[:id])
current_user.vote_for(#song)
#song.plusminus = #song.votes_for
#song.save
respond_to do |format|
format.js { render 'update_votes' }
end
end
def vote_against
#song = Song.find(params[:id])
current_user.vote_against(#song)
respond_to do |format|
format.js { render 'update_votes' }
end
end
def new_songs
#songs = Song.order("id DESC").paginate(:page => params[:page], :per_page => 15)
end
# GET /Songs
# GET /Songs.json
def index
if params[:genre]
#songs = Song.tagged_with(params[:genre]).paginate(:page => params[:page], :per_page => 15)
else
#songs = Song.order('plusminus').paginate(:page => params[:page], :per_page => 15)
end
end
# GET /Songs/1
# GET /Songs/1.json
def show
#comment = Comment.new(song: #song)
#video_tag = YouTubeAddy.extract_video_id(#song.url)
end
# GET /Songs/new
def new
#song = Song.new
end
# GET /Songs/1/edit
def edit
end
# POST /Songs
# POST /Songs.json
def create
#song = Song.new(song_params)
respond_to do |format|
if #song.save
format.html { redirect_to #song, notice: 'Song was successfully created.' }
format.json { render action: 'show', status: :created, location: #song }
else
format.html { render action: 'new' }
format.json { render json: #song.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /Songs/1
# PATCH/PUT /Songs/1.json
def update
respond_to do |format|
if #song.update(song_params)
format.html { redirect_to #song, notice: 'Song was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #song.errors, status: :unprocessable_entity }
end
end
end
# Song /Songs/1
# Song /Songs/1.json
def destroy
#song.destroy
respond_to do |format|
format.html { redirect_to songs_url }
format.json { head :no_content }
end
end
private
def set_song
#song = Song.find(params[:id])
end
def song_params
params.require(:song).permit(:title, :artist, :url, :track, :user_id, :tag_list)
end
end
you are placing js code for 2 actions in the same file.
you have index action and new_songs action in songs_controller.rb, and you put your js in index.js.erb:
$("#songs").html("<%= escape_javascript(render("songs")) %>");
$("#new_songs").html("<%= escape_javascript(render("new_songs")) %>");
move the second line in a file called new_songs.js.erb and you are done.
Related
I'm trying to create a stock market app and I have a button that is breaking my web app. My issue is with this bit of embedded ruby on my
show.html.erb page:
<%= render #stock %>
<div>
<%= link_to "Edit this stock", edit_stock_path(#stock) %> |
<%= link_to "Back to stocks", stocks_path %>
<%= button_to "Delete this stock", #stock, method: :delete %>
</div>
This#stock.destroy line is needed for removing entries for a user. The error rails throws:
Showing C:/stockmarketapp/app/views/stocks/show.html.erb where line #9 raised:
undefined method `destroy' for #<StockQuote::Stock:0x000001f7fc0aa780 #attribution="Data provided for free by IEX (https://iexcloud.io).",
#response_code=200, #avg_total_volume=2261555,
#calculation_price="close", #change=-0.36, #change_percent=-0.00331,
#close=108.41, #close_source="official", #close_time=1654286400058,
#company_name="BlackRock Institutional Trust Company N.A. - iShares Core High Dividend ETF", #currency="USD", #delayed_price=108.4,
#delayed_price_time=1654286390674, #extended_change=0, #extended_change_percent=0, #extended_price=108.41,
#extended_price_time=1654300800004, #high=108.93, #high_source="15
minute delayed price", #high_time=1654286395170, #iex_ask_price=nil,
#iex_ask_size=nil, #iex_bid_price=nil, #iex_bid_size=nil,
#iex_close=108.43, #iex_close_time=1654286330444,
#iex_last_updated=nil, #iex_market_percent=nil, #iex_open=108.81,
#iex_open_time=1654263316934, #iex_realtime_price=nil,
#iex_realtime_size=nil, #iex_volume=nil,
#last_trade_time=1654286394157, #latest_price=108.41,
#latest_source="Close", #latest_time="June 3, 2022",
#latest_update=1654286400058, #latest_volume=876363, #low=108.25,
#low_source="15 minute delayed price", #low_time=1654273215082,
#market_cap=13133871500, #odd_lot_delayed_price=108.395,
#odd_lot_delayed_price_time=1654286390033, #open=108.33,
#open_time=1654263000128, #open_source="official", #pe_ratio=nil,
#previous_close=108.77, #previous_volume=1062893,
#primary_exchange="NYSE ARCA", #symbol="HDV", #volume=876363,
#week52_high=110.91, #week52_low=91.09,
#ytd_change=0.07801100501710605, #is_us_market_open=false>
Extracted source (around line #9):78910
<%= link_to "Edit this stock", edit_stock_path(#stock) %> |
<%= link_to "Back to stocks", stocks_path %>
<%= button_to "Delete this stock", #stock.destroy, method: :delete %>
</div>
Rails.root: C:/stockmarketapp
Application Trace | Framework Trace | Full Trace
app/views/stocks/show.html.erb:9
These are my files related to #stock and #stock.destroy:
class StocksController < ApplicationController
before_action :set_stock, only: %i[ show edit update destroy ]
before_action :correct_user, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!
#api = StockQuote::Stock.new(api_key: "pk_153e93f4bce64c3d87e7d4d3510153ed")
# GET /stocks or /stocks.json
def index
#stocks = Stock.all
end
# GET /stocks/1 or /stocks/1.json
def show
#stocks = Stock.all
end
# GET /stocks/new
def new
#stock = Stock.new
end
# GET /stocks/1/edit
def edit
end
# POST /stocks or /stocks.json
def create
#stock = Stock.new(stock_params)
respond_to do |format|
if #stock.save
format.html { redirect_to stock_url(#stock), notice: "Stock was successfully created." }
format.json { render :show, status: :created, location: #stock }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: #stock.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /stocks/1 or /stocks/1.json
def update
respond_to do |format|
if #stock.update(stock_params)
format.html { redirect_to stock_url(#stock), notice: "Stock was successfully updated." }
format.json { render :show, status: :ok, location: #stock }
else
format.html { render :edit, status: :unprocessable_entity }
format.json { render json: #stock.errors, status: :unprocessable_entity }
end
end
end
# DELETE /stocks/1 or /stocks/1.json
def destroy
#stock.destroy
respond_to do |format|
format.html { redirect_to stocks_url, notice: "Stock was successfully destroyed." }
format.json { head :no_content }
end
end
def correct_user
#ticker = current_user.stocks.find_by(id: params[:id])
redirect_to stocks_path, notice: "Not Autherized to edit this stock" if #ticker.nil?
end
private
# Use callbacks to share common setup or constraints between actions.
def set_stock
#stock = Stock.find(params[:id])
end
# Only allow a list of trusted parameters through.
def stock_params
params.require(:stock).permit(:ticker, :user_id)
end
end
Stock partial:
<% #stock= StockQuote::Stock.quote(stock.ticker) %>
<div id="<%= dom_id stock %>">
<p>
<strong>Ticker:</strong>
<%= #stock.symbol %>
</p>
<p>
<strong>Open</strong>
$<%= #stock.open %>
</p>
<p>
<strong>Price</strong>
$<%= #stock.latest_price %>
</p>
<p>
<strong>Close</strong>
$<%= #stock.close %>
</p>
<p>
<strong>Company Name</strong>
<%= #stock.company_name %>
</p>
<p>
<strong>Primary Exchange</strong>
<%= #stock.primary_exchange %>
</p>
<p>
<strong>Volume</strong>
<%= number_with_delimiter(#stock.volume, :delimiter => ',') %>
</p>
<p>
<strong>Market Cap</strong>
$<%= number_with_delimiter(#stock.market_cap, :delimiter => ',') %>
</p>
</div>
Github Repo: https://github.com/Maikkeru/Stockmarketapp
I assume that am wielding the stock object incorrectly but I don't know where that slipup is occurring. Thanks for your time.
I get this error when trying to show <%= #schedule.title %>, but when I do the same with <%= #lesson.title %> it is working fine for #lesson.
![undefined method `title' for nil:NilClass
]1
The flow is like this.
- A user signs up and creates a clinic, the clinic belongs to the user.
- A clinic has many practitioners and they belongs to the clinic.
- A practitioner has many lessons and schedules, and they belongs to the practitioner.
When I'm on the lesson show page, there is a link to a booking page. It's on this booking page that the error occours.
I know it's saying nil, but both lessons and schedules have been created for that specific practitioner.
Anybody knows why this is happening? I don't understand why I can access #lesson but not #schedule. Any help would be much appreciated.
routes.rb
resources :clinics do
resources :practitioners do
resources :lessons, :lesson_payments, :schedules do
resources :bookings do
end
end
end
end
schedules_controller.rb
class SchedulesController < ApplicationController
before_action :set_schedule, only: [:show, :edit, :update, :destroy]
# GET /schedules
# GET /schedules.json
def index
#schedules = Schedule.all
end
# GET /schedules/1
# GET /schedules/1.json
def show
end
# GET /schedules/new
def new
#schedule = Schedule.new
end
# GET /schedules/1/edit
def edit
end
# POST /schedules
# POST /schedules.json
def create
#schedule = Schedule.new(schedule_params)
respond_to do |format|
if #schedule.save
format.html { redirect_to clinic_practitioner_schedule_path(id: #schedule.id), notice: 'Schedule was successfully created.' }
format.json { render :show, status: :created, location: #schedule }
else
format.html { render :new }
format.json { render json: #schedule.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /schedules/1
# PATCH/PUT /schedules/1.json
def update
respond_to do |format|
if #schedule.update(schedule_params)
format.html { redirect_to clinic_practitioner_schedule_path(#schedule), notice: 'Schedule was successfully updated.' }
format.json { render :show, status: :ok, location: #schedule }
else
format.html { render :edit }
format.json { render json: #schedule.errors, status: :unprocessable_entity }
end
end
end
# DELETE /schedules/1
# DELETE /schedules/1.json
def destroy
#schedule.destroy
respond_to do |format|
format.html { redirect_to clinic_practitioner_schedules_url, notice: 'Schedule was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_schedule
#schedule = Schedule.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def schedule_params
params.require(:schedule).permit(:title, :start, :end, :practitioner_id, :account_id)
end
end
bookings_controller.rb
class BookingsController < ApplicationController
before_action :set_lesson, only: [:new]
def new
#account = Account.new
#user = User.new
#patient = Patient.new
#booking = Booking.new
#lesson_payment = LessonPayment.new
#schedule = Schedule.find_by_id(params[:id])
end
def create
create_patient_charge
create_patient_account
#user = User.new(user_params)
#user.account_id = #account.id
respond_to do |format|
if #user.save
create_patient_profile
create_patient_booking
create_patient_lesson_payment
auto_login(#user)
UserMailer.new_signup_booking_admin(#user, #booking).deliver_later
UserMailer.new_signup_booking_client(#user, #booking).deliver_later
format.html { redirect_to dashboard_url, notice: 'Your account was successfully created.' }
format.json { render :show, status: :created, location: #user }
else
format.html { redirect_back fallback_location: root_path, alert: 'An error occurred while sending this request.' }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
private
def set_lesson
#lesson = Lesson.find(params[:lesson_id])
end
def user_params
params.require(:user).permit(:email, :password, :time_zone)
end
def create_patient_account
#account = Account.new()
#account.status = 'active'
#account.account = 'prefix-' + SecureRandom.hex(4)
#account.account_type = 'client'
#account.save
end
def create_patient_profile
#patient = Patient.new()
#patient.firstname = params[:user][:patient][:patient_first_name]
#patient.lastname = params[:user][:patient][:patient_last_name]
#patient.phone = params[:user][:patient][:patient_phone]
#patient.user_id = #user.id
#patient.account_id = #user.account_id
#patient.save
end
def create_patient_booking
#lesson = Lesson.find(params[:user][:booking][:lesson_id])
#booking = Booking.new()
#booking.lesson_id = params[:user][:booking][:lesson_id]
#booking.schedule_id = params[:user][:booking][:schedule_id]
#booking.patient_id = #patient.id
#booking.account_id = #user.account_id
#booking.title = #lesson.title
#booking.cost = #lesson.cost
#booking.status = 'Booked'
#booking.save
#schedule = Schedule.find(params[:user][:booking][:schedule_id])
#booking.practitioner_id = #schedule.practitioner_id
#booking.start = #schedule.start
#booking.refunded = 0
#booking.save
#schedule.title = 'Booked'
#schedule.save
end
def create_patient_lesson_payment
#lesson_payment = LessonPayment.new()
#lesson_payment.status = 'Paid'
#lesson_payment.date = Date.today
#lesson_payment.cost = #lesson.cost
#lesson_payment.service = #lesson.title
#lesson_payment.booking_id = #booking.id
#lesson_payment.account_id = #user.account_id
#lesson_payment.save
end
end
This is where I link to the booking page
show.html.erb
<p id="notice"><%= notice %></p>
<%= link_to new_clinic_practitioner_lesson_booking_path(:lesson_id => #lesson.id), class: "course-btn" do %><i class="fa fa-calendar-plus-o"></i> Book This Lesson<% end %>
<p>
<strong>Image:</strong>
<%= #lesson.image %>
</p>
<p>
<strong>Title:</strong>
<%= #lesson.title %>
</p>
<p>
<strong>Duration:</strong>
<%= #lesson.duration %>
</p>
<p>
<strong>Cost:</strong>
<%= #lesson.cost %>
</p>
<p>
<strong>Category:</strong>
<%= #lesson.category %>
</p>
<p>
<strong>Language:</strong>
<%= #lesson.language %>
</p>
<p>
<strong>Level:</strong>
<%= #lesson.level %>
</p>
<p>
<strong>Description:</strong>
<%= #lesson.description %>
</p>
<p>
<strong>Practitioner:</strong>
<%= #lesson.practitioner_id %>
</p>
<p>
<strong>Account:</strong>
<%= #lesson.account_id %>
</p>
<%= link_to 'Edit', edit_clinic_practitioner_lesson_path(#lesson) %> |
<%= link_to 'Back', clinic_practitioner_lessons_path %>
new.html.erb
<h1>New Booking</h1>
<%= render 'form', booking: #booking %>
<%= link_to 'Back', clinic_practitioner_lesson_bookings_path %>
_form.html.erb
<table class="table table-bordered">
<thead>
<tr>
<th>Slots In The User's Time Zone</th>
<th>Price</th>
<th>Service Provider</th>
<th>Booking Button</th>
</tr>
</thead>
<tbody>
<tr>
<td><%= #lesson.title %></td>
<td><%= #schedule.title %></td>
</tr>
</tbody>
</table>
I am noticing that in you are initializing #schedule like this in your bookings_controller new method:
#schedule = Schedule.find_by_id(params[:id])
But, you don't have any params[:id] in your parameters that are:
{'clinic_id'=>'50','practitioner_id'=>'27','lesson_id'=>'15'}
This is why your #schedule is nil
Assuming, there is a has_many association between practitioner and schedule, and you want to display the title of first schedule of the practitioner, you can do it it like this:
#schedule = Schedule.find_by_practitioner_id(params[:practitioner_id])
I want to create, edit and delete db entity from other controller than generated by scaffold. I want to have validation, create and deletion without redirection. I don't want to use generated controller because i want to create at least 2 types of entities from one controller.
For now i have create without redirect but i don't have notification about entity creation.
This controller should support crud operations:
class SmartHomeController < ApplicationController
layout 'smart_home'
def index
#name = 'Home';
end
def settings
#name = 'Settings';
#place = Place.new;
#all_places = Place.all;
respond_to do |format|
if #place.save
format.html { redirect_to #place, :notice => 'A was successfully created.' }
else
# render new with validation errors
format.html { render :action => "settings" }
end
end
end
end
scaffold generated controller:
class PlacesController < ApplicationController
before_action :set_place, only: [:show, :edit, :update, :destroy]
# GET /places
# GET /places.json
def index
#places = Place.all
end
# GET /places/1
# GET /places/1.json
def show
end
# GET /places/new
def new
#place = Place.new
end
# GET /places/1/edit
def edit
end
# POST /places
# POST /places.json
def create
#place = Place.new(place_params)
respond_to do |format|
if #place.save
format.html { redirect_to smart_home_settings_path, notice: 'Place was successfully created.' }
format.json { render :show, status: :created, location: #place }
else
format.html { render :new }
format.json { render json: #place.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /places/1
# PATCH/PUT /places/1.json
def update
respond_to do |format|
if #place.update(place_params)
format.html { redirect_to #place, notice: 'Place was successfully updated.' }
format.json { render :show, status: :ok, location: #place }
else
format.html { render :edit }
format.json { render json: #place.errors, status: :unprocessable_entity }
end
end
end
# DELETE /places/1
# DELETE /places/1.json
def destroy
#place.destroy
respond_to do |format|
format.html { redirect_to places_url, notice: 'Place was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_place
#place = Place.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def place_params
params.require(:place).permit(:name, :hw)
end
end
Could you guide me how to achieve that?
Edit. New code.
Page:
<div class="demo-cards mdl-cell mdl-cell--4-col mdl-cell--8-col-tablet mdl-grid mdl-grid--no-spacing"
style="width: 420px">
<div class="demo-updates mdl-card mdl-shadow--2dp mdl-cell mdl-cell--4-col mdl-cell--4-col-tablet mdl-cell--12-col-desktop">
<div class="mdl-card__title mdl-card--expand mdl-color--teal-300">
<h2 class="mdl-card__title-text">All places</h2>
</div>
<div class="mdl-card__supporting-text mdl-color-text--grey-600">
<ul class="demo-list-item mdl-list">
<% #all_places.each do |place| %>
<li class="mdl-list__item">
<span class="mdl-list__item-primary-content">
<%= place.name %>: <%= place.hw %> <%= link_to 'Destroy', place, controller: 'smart_home', action: 'delete_place', data: { confirm: 'Are you sure?' } %>
</span>
</li>
<% end %>
</ul>
</div>
</div>
</div>
<div class="demo-cards mdl-cell mdl-cell--4-col mdl-cell--8-col-tablet mdl-grid mdl-grid--no-spacing"
style="width: 420px">
<div class="demo-updates mdl-card mdl-shadow--2dp mdl-cell mdl-cell--4-col mdl-cell--4-col-tablet mdl-cell--12-col-desktop">
<div class="mdl-card__title mdl-card--expand mdl-color--teal-300">
<h2 class="mdl-card__title-text">Create place</h2>
</div>
<div class="mdl-card__supporting-text mdl-color-text--grey-600">
<table class="mdl-data-table mdl-js-data-table mdl-data-table--selectable mdl-shadow--2dp create-place-table">
<%= form_for #place, url: smart_home_create_path do |f| %>
<tr>
<td>
<div class="mdl-textfield mdl-js-textfield">
<%= f.label :name, 'Name', class: 'mdl-textfield__label' %>
<%= f.text_field :name, class: 'mdl-textfield__input' %>
</div>
</td>
</tr>
<tr>
<td>
<div class="mdl-textfield mdl-js-textfield">
<%= f.label :hw, class: 'mdl-textfield__label' %>
<%= f.text_field :hw, class: 'mdl-textfield__input' %>
</div>
</td>
</tr>
<tr>
<td>
<%= f.submit "Create", class: 'mdl-button mdl-js-button mdl-button--raised mdl-js-ripple-effect' %>
</td>
</tr>
<% end %>
</table>
</div>
</div>
</div>
Controller:
class PlacesController < ApplicationController
before_action :set_place, only: [:show, :edit, :update, :destroy]
# GET /places
# GET /places.json
def index
#places = Place.all
end
# GET /places/1
# GET /places/1.json
def show
end
# GET /places/new
def new
#place = Place.new
end
# GET /places/1/edit
def edit
end
# POST /places
# POST /places.json
def create
#place = Place.new(place_params)
respond_to do |format|
if #place.save
format.html { redirect_to smart_home_settings_path, notice: 'Place was successfully created.' }
format.json { render :show, status: :created, location: #place }
else
format.html { render :new }
format.json { render json: #place.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /places/1
# PATCH/PUT /places/1.json
def update
respond_to do |format|
if #place.update(place_params)
format.html { redirect_to #place, notice: 'Place was successfully updated.' }
format.json { render :show, status: :ok, location: #place }
else
format.html { render :edit }
format.json { render json: #place.errors, status: :unprocessable_entity }
end
end
end
# DELETE /places/1
# DELETE /places/1.json
def destroy
#place.destroy
respond_to do |format|
format.html { redirect_to smart_home_settings_path, notice: 'Place was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_place
#place = Place.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def place_params
params.require(:place).permit(:name, :hw)
end
end
Deletion works but no confirm:
Page:
<%= link_to 'Destroy', delete_place_path(id: place.id), data: {:confirm => 'Are you sure?'}, :method => :delete %>
Controller:
def delete_place
place = Place.find(params[:id])
place.destroy
respond_to do |format|
format.html { redirect_to smart_home_settings_path, notice: 'Place was successfully destroyed.' }
format.json { head :no_content }
end
end
Routes:
get 'delete_place/:id' => 'smart_home#delete_place', as: :delete_place
Edit:
Javascript include was missed
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
<%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
<%= csrf_meta_tags %>
In my application I have stories and substories. Substories are nested inside stories and on the storiesindex.html.erb. I'm looping trough all the stories, and inside I'm looping through all the substories.
here is the code:
<% #stories.each do |story| %>
<%= story.title %>
<%= story.plot %>
<%= link_to 'Show', story_path(story) %>
<%= link_to 'Edit', edit_story_path(story) %>
<%= link_to "Delete", story_path(story), method: :delete, data: { confirm: "Are you sure?" } %>
<% story.substories.each do |substories| %>
<%= substories.title %>
<%= substories.subplot %>
<% end %>
<% end %>
<%= link_to 'New Story', new_story_path %>
This works fine, but I want to link to the edit page of each substory by passing the following argument inside the second loop:
<%= link_to 'Edit', edit_story_substory_path(substory.story, substory) %>
I get a NameError in Stories#index undefined local variable or method 'substory', however this work fine in the substories index.html.erb file.
I've also tried the following:
<%= link_to 'Edit', edit_story_substory_path(#substory.story, #substory) %>
for which I get a NoMethodError in Stories#index undefined method 'story' for nil:NilClass
Here are my routes models and controllers:
#routes.rb
resources :stories do
resources :substories
end
#story.rb
has_many :substories
#substory.rb
belongs_to :story
stories_controller.erb
before_action :set_story, only: [:show, :edit, :update, :destroy]
def index
#stories = Story.all
end
def show
#substories = Substory.where(story_id: #story.id).order("created_at DESC")
end
def new
#story = Story.new
end
def edit
end
def create
#story = Story.new(story_params)
respond_to do |format|
if #story.save
format.html { redirect_to root_path, notice: 'Story was successfully created.' }
format.json { render :show, status: :created, location: root_path }
else
format.html { render :new }
format.json { render json: root_path.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #story.update(story_params)
format.html { redirect_to root_path, notice: 'Story was successfully updated.' }
format.json { render :show, status: :ok, location: root_path }
else
format.html { render :edit }
format.json { render json: #story.errors, status: :unprocessable_entity }
end
end
end
def destroy
#story.destroy
respond_to do |format|
format.html { redirect_to stories_url, notice: 'Story was successfully destroyed.' }
format.json { head :no_content }
end
end
private
def set_story
#story = Story.find(params[:id])
end
def story_params
params.require(:story).permit(:title, :plot)
end
substories_controller.erb
before_action :set_substory, only: [:show, :edit, :update, :destroy]
before_action :set_story
def index
#substories = Substory.all
end
def show
end
def new
#substory = Substory.new
end
def edit
end
def create
#substory = Substory.new(substory_params)
#substory.user_id = current_user.id
#substory.story_id = #story.id
if
#substory.save
redirect_to #story
else
render 'new'
end
end
def update
respond_to do |format|
if #substory.update(substory_params)
format.html { redirect_to root_path, notice: 'Story was successfully updated.' }
format.json { render :show, status: :ok, location: root_path }
else
format.html { render :edit }
format.json { render json: #story.errors, status: :unprocessable_entity }
end
end
end
def destroy
#substory.destroy
redirect_to root_path
end
private
def set_story
#story = Story.find(params[:story_id])
end
def set_substory
#substory = Substory.find(params[:id])
end
def substory_params
params.require(:substory).permit(:title, :subplot)
end
What am I missing?
<% story.substories.each do |substory| %>
<%= substory.title %>
<%= substory.subplot %>
<% if substory %>
<%= link_to 'Edit', edit_story_substory_path(substory.story, substory) %>
<% end %>
<% end %>
You just made a typo. #substory would work too if you declare it on your Stories#index
So, I have an app that allows users to up vote/like songs (using this gem). However, I'd like the songs with higher votes to be ranked up the list. As currently, they only appear in the order in which they were uploaded. How do I accomplish this?
songs#index.html.erb
<div id="layout-1">
<div class="left-side">
<h3>Songs</h3>
<ol>
<% #songs.each do |song| %>
<li><%= link_to song.title, song %><br></li>
<%=link_to '▲'.html_safe, vote_for_song_path(song), :remote => true, :method => :put %>
<%#=link_to '▼'.html_safe, vote_against_song_path(song), :remote => true, :method => :put %> |
Submitted <%= time_ago_in_words(song.created_at) + " ago" %>
<span class="comments"> | <%= pluralize(song.comments.size, 'comment') %></span> | <span class="votes"><%= pluralize(song.votes.count, 'like') %></span><br />
<%#= link_to 'Show', song, class: "button small secondary" %>
<%= link_to('Edit', edit_song_path(song), class: "button small secondary") if can? :update, song %>
<%= link_to('Destroy', song, method: :delete, data: {confirm: 'Are you sure?'}, class: "button small secondary") if can? :destroy, song %>
<% end %>
</ol>
</div>
<div class="right-side">
<%= image_tag('delorean.jpg')%>
</div></div>
<br />
songs_controller.rb
class SongsController < ApplicationController
before_filter :authenticate_user!, only: [:create ,:edit, :update, :destroy, :vote_for_song]
before_action :set_song, only: [:show, :edit, :update, :destroy, :vote_for_song]
def vote_for
#song = Song.find(params[:id])
current_user.vote_for(#song)
respond_to do |format|
format.js { render 'update_votes' }
end
end
def vote_against
#song = Song.find(params[:id])
current_user.vote_against(#song)
respond_to do |format|
format.js { render 'update_votes' }
end
end
# GET /Songs
# GET /Songs.json
def index
#songs = Song.all
end
# GET /Songs/1
# GET /Songs/1.json
def show
#comment = Comment.new(song: #song)
end
# GET /Songs/new
def new
#song = Song.new
end
# GET /Songs/1/edit
def edit
end
# POST /Songs
# POST /Songs.json
def create
#song = Song.new(song_params)
respond_to do |format|
if #song.save
format.html { redirect_to #song, notice: 'Song was successfully created.' }
format.json { render action: 'show', status: :created, location: #song }
else
format.html { render action: 'new' }
format.json { render json: #song.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /Songs/1
# PATCH/PUT /Songs/1.json
def update
respond_to do |format|
if #song.update(song_params)
format.html { redirect_to #song, notice: 'Song was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #song.errors, status: :unprocessable_entity }
end
end
end
# Song /Songs/1
# Song /Songs/1.json
def destroy
#song.destroy
respond_to do |format|
format.html { redirect_to songs_url }
format.json { head :no_content }
end
end
private
def set_song
#song = Song.find(params[:id])
end
def song_params
params.require(:song).permit(:title, :artist, :bio, :track, :user_id)
end
end
Your Song model should have a plusminus field or somesuch (looking at the gem briefly, that looks like plusminus, which is the sum of up plus down votes), which counts the number of thumbs-ups a given song has received. Then, simply query with a sort on that field:
def vote_for
#song = Song.find(params[:id])
current_user.vote_for(#song)
#song.plusminus = #song.voted_for
#song.save
respond_to do |format|
format.js { render 'update_votes' }
end
end
def index
#songs = Song.order("plusminus")
end