user3787971
user3787971

Reputation: 457

NoMethodError in Lines#show

UPDATE: The answer bellow is correct. Just wanted to update what I did to solve the problem. First I had to delete all my previous lines in the rails console.

Then I used the bye bug gem in my lines controller at the bottom of the create method to discover where the next bug occurred. I created a test line that I needed to delete again. so I ran

Line.last.delete in console.

This is the way my lines controller create method looks now (working no bugs)

def create
    if user_signed_in?
        @line = Line.create(line_params)
        if @line

        if params[:line][:previous_line_id].empty?
                @line.story = Story.create
                @line.save
            else
                @line.story = @line.previous_line.story
                @line.save
            end

            redirect_to line_path(@line)
        else
            flash[:error] = @line.errors
            redirect_to line_path(Line.find(params[:line][:previous_line_id]))
        end

    else

Finally I ran @Lines.each { |line| line.update.attribute(:story_id: 3)}

This gave the necessary association between lines and story.

ORIGINAL POST BELLOW.

I'm getting this error in my rails app. I think that when I create a new line or start a story, it doesn't automatically add it to a story object. I've listed my show.html.erb file as well as my lines controller.rb file.

What am I missing? How do I get the controller to add data to the story object correctly?

Thanks!

enter image description here

I added a few lines of code to my lines controller:

class LinesController < ApplicationController

def new
    params[:previous_line_id].nil? ? @line = Line.new : @line = Line.find(params[:previous_line_id]).next_lines.create

    @lines = @line.collect_lines

    @ajax = true if params[:ajax]
    render :layout => false if params[:ajax]
    if @line.previous_line
        @line.update_attribute(:story_id, @line.previous_line.story.id)
    else
        story = Story.create
        @line.story = story
        @line.save
    end
end

def create
    if user_signed_in?
        @line = Line.create(line_params)
        if @line
            redirect_to line_path(@line)
        else
            flash[:error] = @line.errors
            redirect_to line_path(Line.find(params[:line][:previous_line_id]))
        end
    else

        flash[:error] = "Please sign in or register before creating a line!"
        unless params[:line][:previous_line_id].empty?
            redirect_to line_path(Line.find(params[:line][:previous_line_id]))
        else
            redirect_to root_path
        end
    end
end



# params[:id] should correspond to the first line of the story.
# if params[:deeper_line_id] is not nil, that means that they want to render up to the nested line id
def show
    @lines = Line.find(params[:id]).collect_lines
    @next_lines = @lines.last.next_lines.ranked
    @lines.last.update_attribute(:score, @lines.last.score + 1)
end

def select_next
    @line = Line.find(params[:id])
    @line.update_attribute(:score, @line.score + 1)
    @lines = [@line]

    @next_lines = @line.next_lines.ranked
    render :layout => false
end

def send_invite
    if user_signed_in?
        UserInvite.send_invite_email(current_user,Line.find(params[:id]), params[:email]).deliver
        flash[:notice] = "Your invite was sent!"
    else
        flash[:error] = "Please sign in"
    end
    redirect_to Line.find(params[:id])
end

private

def line_params
    params.require(:line).permit(:text, :previous_line_id, :user_id)
end

end

I added these lines to the controller pictured above

    if @line.previous_line
        @line.update_attribute(:story_id, @line.previous_line.story.id)
    else
        story = Story.create
        @line.story = story
        @line.save
    end

Here is my show.html.erb file

<div class="row">
<div class="col-lg-2">
</div>


<div class="box-container col-lg-7  ">


    <div id="story" class="box">
        <% @lines.each do |line| %>
            <span class="story-line" data-id="<%=line.id%>"><%= link_to line.text, '#', :class=>"story-line" %></span>
        <% end %>

    </div>

    <div id="next-steps">
        <%= render 'next_steps' %>
    </div>


<span style="font-size:.9em; margin-bottom:15px; display:block;">*If the links don't work, try refreshing.</span>

</div>

<div class="col-lg-2" style="padding-right:25px;">
    <%= render 'invite' %>
    Your Fellow Collaborators: <br />
    <div class="collaborators">
        <% @lines.last.story.collaborators.uniq.each do |collaborator| %>
            <%= link_to profile_path(:id => collaborator.id) do %>
                <%= image_tag collaborator.profile_image_uri, :class => "prof-icon" %>
            <% end %>
        <% end %>
    </div>

Story model

class Story < ActiveRecord::Base

has_many :lines
has_and_belongs_to_many :collaborators, :class_name => "User", :join_table => "collaborators_stories", :association_foreign_key => :collaborator_id


def first_line

    self.lines.first_lines.first_lines.first
end
end

Here is my lines.rb file

class Line < ActiveRecord::Base

scope :first_lines, -> { where previous_line_id: nil}
scope :ranked, -> { order("score + depth DESC")}

belongs_to :user
belongs_to :story
belongs_to :previous_line, :class_name => "Line", :foreign_key => "previous_line_id"
has_many :next_lines, :class_name => "Line", :foreign_key => "previous_line_id"
validates_presence_of :text

after_create :update_depths


def update_depths
    line = self.previous_line
    while !line.nil?
        line.update_attribute(:depth, line.depth + 1)
        line = line.previous_line
    end
end

def first_line
    line = self
    while !line.previous_line.nil?
        line = line.previous_line
    end
    line
end

def collect_lines
    line = self
    lines = [self]
    while !line.previous_line.nil?
        lines.unshift(line.previous_line)
        line = line.previous_line
    end
    lines
end

end

Upvotes: 0

Views: 112

Answers (1)

Jorge de los Santos
Jorge de los Santos

Reputation: 4633

Problem is orphaned lines in your database. Look for them and associate it to a story, or delete it:

How to find orphaned records: http://antonzolotov.com/2013/01/26/how-to-find-and-delete-orphaned-records-with-ruby-on-rails.html

Then review the create method to ensure a line should be part of a story:

#short example review activerecord relations

@story = Story.find(params[:story_id])
story.lines.create(line_params)

That should work.

EDIT:

def self.find_orphan_ids 
  Lines.where([ "user_id NOT IN (?) OR story_id NOT IN (?)", User.pluck("id"), Story.pluck("id") ]).destroy_all 
end

Upvotes: 1

Related Questions