Rails - Liking Comments Made on Posts - NoMethodError - ruby-on-rails

For my application, I have Users, who can Create Project Postings. On each Project Posting, they can make comments that I have made a Blogupdate model. I want users to be able to like Blogupdates made on each Project page.
So, I created a Bloglike model. But when I try to render a LIKE/UNLIKE button, I get the following error:
NoMethodError in Projects#blogs
undefined method `bloglikes_path'
Extracted source (around line #11):
11: <%= form_for(current_user.bloglikes.build(blogupdate_id: blogupdate.id)) do |f| %>
Question: As a note, I have not built up the controller for the actual create/destroy function in my bloglikes controller; but looking at my attached code below, does somebody know how I can resolve this error so the like/unfollow button renders?
schema.rb
create_table "bloglikes", :force => true do |t|
t.integer "user_id"
t.integer "blogupdate_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
add_index "bloglikes", ["blogupdate_id"], :name => "index_bloglikes_on_blogupdate_id"
add_index "bloglikes", ["user_id", "blogupdate_id"], :name => "index_bloglikes_on_user_id_and_blogupdate_id", :unique => true
add_index "bloglikes", ["user_id"], :name => "index_bloglikes_on_user_id"
user.rb
has_many :bloglikes, foreign_key: "user_id"
has_many :liked_blogupdates, through: :bloglikes, source: :blogupdate
blogupdate.rb
has_many :bloglikes, foreign_key: "blogupdate_id"
has_many :liked_by, through: :bloglikes, source: :user
def liking_blogupdate?(blogupdate)
bloglikes.find_by_blogupdate_id(blogupdate.id)
end
def like_blogupdate!(blogupdate)
bloglikes.create!(blogupdate_id: blogupdate.id)
end
def blogupdate_unlike!(blogupdate)
bloglikes.find_by_blogupdate_id(blogupdate.id).destroy
end
bloglike.rb
class Bloglike < ActiveRecord::Base
attr_accessible :blogupdate_id
belongs_to :user, foreign_key: "user_id"
belongs_to :blogupdate, foreign_key: "blogupdate_id"
end
projects_controller.rb
def blogs
#project = Project.find(params[:id])
#blogupdates = #project.blogupdates.newest.page(params[:blogupdates_page]).per_page(5)
end
views/projects/blogs.html.erb
<%= render 'blogs' %>
views/projects/_blogs.html.erb
<%= render #blogupdates %>
views/blogupdates/_blogupdates.html.erb
<%= blogupdate.liked_by.count %>
<% if current_user.liking_blogupdate?(blogupdate) %>
<%= form_for(current_user.bloglikes.find_by_blogupdate_id(blogupdate),
html: { method: :delete }) do |f| %>
<%= f.submit "UNLIKE", class: "btn btn-medium" %>
<% end %>
<% else %>
<%= form_for(current_user.bloglikes.build(blogupdate_id: blogupdate.id)) do |f| %>
<div><%= f.hidden_field :blogupdate_id %></div>
<%= f.submit "LIKE", class: "btn btn-medium btn-primary" %>
<% end %>
<% end %>
<p><%= raw blogupdate.content %></p>
UPDATE: As noted below by #Dan, I forgot to update the routes.rb file. I added "resources :bloglikes" and it worked now.

You didn't post your routes.rb file but I'd wager that is where the problem is at. An undefined method related to routes (e.g. bloglikes_path) typically indicates you've not defined the routes.
Add resources :bloglikes to your project's routes.rb file and see if that resolves the issue.

Related

Rails- How can I create view for nasted tables

I want to get data like this in the show.html.erb , but it doesn't work.
How can I get data from spot table?
here is the code.
show.html.erb
<% #planaction.each do |action| %>
<hr>
<%= action.spot.name %>
<%= action.spot.description %>
<hr>
<%= action.title %>
<%= action.experience %>
<% end %>
plan.rb
class Plan < ActiveRecord::Base
has_many :plan_actions
end
plan_action.rb
class PlanAction < ActiveRecord::Base
belongs_to :plan
has_one :spot
end
spot.rb
class Spot < ActiveRecord::Base
belongs_to :plan_action
end
plan_actions_controller.erb
class PlanPagesController < ApplicationController
def show
#plan = Plan.find(params[:id])
#planaction = #plan.plan_actions
end
end
and error message here
undefined method `name' for nil:NilClass
and here is migration file for spot table.
class CreateSpots < ActiveRecord::Migration
def change
create_table :spots do |t|
t.integer :spot_id
t.integer :plan_action_id
t.string :name
t.text :description
t.time :time_open
t.time :time_close
t.date :dayoff
t.string :address
t.integer :tel
t.string :image
t.string :image2
t.string :image3
t.timestamps null: false
end
end
end
Looks good to me.
The issue is probably (can't be certain without seeing your logs) that the plan_action doesn't have an associated spot record.
To fix this, you should use some conditional logic:
<% #planaction.each do |action| %>
<hr>
<% if action.spot %>
<%= action.spot.name %>
<%= action.spot.description %>
<hr>
<% end %>
<%= action.title %>
<%= action.experience %>
<% end %>
Again, this is speculation. I wrote the answer because I felt it best to provide some sort of idea as to how to resolve it. The above should work.
I also think as Rich Peck that you don't have a record in spots table with plan_action_id corresponding to a plan action.
Following rails convention, I suggest the following:
class PlanAction < ActiveRecord::Base
belongs_to :plan
has_one :spot
delegate :name, :description, to: :spot, prefix: true, allow_nil: true
end
and in your view:
<%= action.spot_name %>
<%= action.spot_description %>
Finally, get your validations corrected. For example, if a plan_action should have a spot, then you need to use nested forms for both spot and plan action.

How to show results based on sql result data

I'm using Closure tree idea in my new website.
In one of the show views I want to select data by the id (1-level descendant) or if the id is null the first level.
How do I connect sql with set result?
The Query:
select id,name
from tags t
join tag_hierarchies th (t.id = th.ancestor_id)
where t.id=nvl(?,0) and th.generations=1
Code so far(problem on app/views/show.erb):
db/schema.rb:
create_table "tags" do |t|
t.string "name", :null=>false
t.boolean "isCat", :default => true
end
create_table "tag_hierarchies", :id => false do |t|
t.integer "ancestor_id", :null => true
t.integer "descendant_id", :null => false
t.integer "generations", :null => false
end
add_foreign_key(:tag_hierarchies, :tags, :column => 'ancestor_id')
add_foreign_key(:tag_hierarchies, :tags, :column => 'descendant_id')
app/models/tag.rb
class Tag < ActiveRecord::Base
#attr_accessible :name, :isCat
validates :name, uniqueness: false, allow_blank: false
end
app/models/Tag_Hierarchie.rb
class TagHierarchie < ActiveRecord::Base
#attr_accessible :ancestor_id, :descendant_id, :generations
end
app/views/show.erb
<% provide(:title, category_name_or_constant(#tags)) %>
<h1><%= category_name_or_constant(#tags)%></h1>
<div class="row">
<div class="span6 offset3">
<%= for(<<here goes the sql by the Closure tree >>) do |f| %>
<%= link_to tag.name, tag %>
<% end %>
</div>
</div>
Add static method (or scope, if you prefer) to your Tag model:
app/models/tag_hierarchy.rb
class TagHierarchy
belongs_to :tag, foreign_key: :ancestor_id
end
app/models/tag.rb
class Tag
has_many :tag_hierarchies, foreign_key: :ancestor_id
def self.descendants(id = nil)
id ||= 0
self.where(id: id).joins(:tag_hierarchies).where(tag_hierarchies: {generations: 1})
end
end
Create a controller:
rake g controller TagsController
Add code to your controller:
app/controllers/tags_controller.rb
class TagsController < ApplicationController
def index
#descendants = Tag.descendants
end
def show
#descendants = Tag.descendants(params[:id])
end
end
Then use all the stuff in your views:
app/views/tags/show.html.erb:
<div class="row">
<div class="span6 offset3">
<%= #descendants.each do |tag| %>
<%= link_to tag.name, tag %>
<%# you can also use tag.tag_hierarchies here %>
<% end %>
</div>
</div>
I suggest you read some tutorials and/or docs on Rails:
Active Record Associations
Rails Routing from the Outside In
Getting Started with Rails

Active record "date" and "nationality" function giving me error. (Undefined method)

I am trying to create a profile page where I can input "born_on". It will be using the
class CreateWineMakers < ActiveRecord::Migration
def change
create_table :wine_makers do |t|
t.string :name
t.date :born_on
t.text :nationality
t.text :profile
t.text :wine
t.integer :wine_list_id
t.timestamps
end
add_index :wine_makers, :wine_list_id
end
end
Here is my view file.
<%= simple_form_for WineMaker.new do |f| %>
<%= f.input :name %>
<%= f.input :profile %>
<%= f.input :wine %>
<%= f.input :born_on %>
<br/>
<%= f.submit "Create", :class => 'btn btn-primary' %>
<% end %>
The "born_on" is giving me error saying the method is not defined. I am confused since all other inputs are working except "born_on" and "nationality". Before, my "born_on" was named "birth_date", and I thought the naming convention was wrong and changed it to "born_on". Here is the controller.
class WineMakersController < ApplicationController
def new
#wine_maker = WineMaker.new
end
def create
#wine_maker = WineMaker.create(wine_maker_params)
redirect_to wine_list_path(#wine_list)
end
def show
end
private
def wine_maker_params
params.require(:wine_maker).permit(:name, :born_on, :nationality, :profile, :wine )
end
end
This seems like such an easy question that I couldn't find similar problems..
Thank you.

can't write unknown attribute `scrapbook_entry_id'

Attempting to add data to a join table of scrapbook_entries which has_one :scrapbook and has_one :recipe.
:recipe and :scrapbook already exist. I am trying to add them to link them with the scrapbook_entries table.
form_for adding to scrapbook_entries table:
<%= form_for(#scrapbook_entry, :url => scrapbook_entries_path(params[:id])) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="field">
<%=f.select(:scrapbook_id, current_user.scrapbooks.collect {|p| [ p.name, p.id ] }, {prompt: 'Select Scrapbook...'})%>
<%= f.hidden_field :recipe_id, :value => #recipe.id %>
</div>
<%= f.submit "Save", class: "btn btn-large btn-primary" %>
<% end %>
scrapbook_entries_controller:
def create
#recipe = Recipe.find(params[:scrapbook_entry][:recipe_id])
#scrapbook = current_user.scrapbooks.find(params[:scrapbook_entry][:scrapbook_id])
#entry = #scrapbook.scrapbook_entries.build(scrapbook: #scrapbook)
if #entry.save
flash[:success] = "Added '#{#recipe.name}' to scrapbook '#{#scrapbook.name}'"
else
flash[:error] = "Could not add to scrapbook"
end
redirect_to #recipe
end
scrapbook.rb
has_many :recipes, through: :scrapbook_entries
has_many :scrapbook_entries
recipe.rb
has_many :scrapbooks, through: :scrapbook_entries
scrapbook_entry.rb
has_one :recipe
has_one :scrapbook
On submitting the form to the controller I am getting a error:
can't write unknown attribute `scrapbook_entry_id'
Can anyone tell me what I am doing wrong?
Update:
schema.rb
create_table "scrapbook_entries", force: true do |t|
t.integer "scrapbook_id"
t.integer "recipe_id"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "user_id"
end
Your scrapbook_entr.rb should contain
belongs_to :recipe
belongs_to :scrapbook
and not has_one!
You always use belongs_to when your table contains a foreign key to another table, which in this case definitely is the case!

Why doesn't my user follow/unfollow button work?

I am working on building an application (following Michael Hartl's chapter 11) where users can follow projects that are created by other users.
I created a ProjectRelationship model to hold two components: follower_id for the users and projectuser_id for the projects. The foreign keys have been set up as such.
Right now, my _follow_form.html.erb page renders "follow" or "unfollow" depending on whether the current_user is following the project. Please see my code below and see what I am missing.
Right now, the follow button is generated on each project show page. But when I click the button follow button that is generated by _follow.html.erb, it does not seem to follow the project or update the count when I call #project.followers.count as the POST is not happening.
And thus, when I click follow button, the URL becomes all jumbled. See example:
#Goes from
domain.com/projects/21
#to
domain.com/projects/21?utf8=%E2%9C%93&authenticity_token=5EQmU0EkHB5yKDYakqL78piMWzZl0CfdpHFEqBeQiN4%3D&project_relationship%5Bprojectuser_id%5D=21&commit=Follow%22
**Update:
It seems to work now, but I'm not sure if I really changed anything but got rid of the follower_id index :unique => true through a migration change.
schema.rb
create_table "project_relationships", :force => true do |t|
t.integer "follower_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.integer "projectuser_id"
end
add_index "project_relationships", ["follower_id"], :name => "index_project_relationships_on_follower_id", :unique => true
add_index "project_relationships", ["projectuser_id"], :name => "index_project_relationships_on_projectuser_id"
routes.rb
resources :projects do
resources :comments
member do
get :following
end
end
resources :project_relationships, only: [:create, :destroy]
project_relationship.rb
class ProjectRelationship < ActiveRecord::Base
attr_accessible :projectuser_id
belongs_to :user, foreign_key: "follower_id"
belongs_to :project, foreign_key: "projectuser_id"
end
project.rb
has_many :project_relationships, foreign_key: "projectuser_id"
has_many :favorited_by, through: :project_relationships, source: :user
user.rb
has_many :project_relationships, foreign_key: "follower_id"
has_many :followed_projects, through: :project_relationships, source: :project
def following_project?(project)
project_relationships.find_by_follower_id(project.id)
end
def follow_project!(project)
project_relationships.create!(projectuser_id: project.id)
end
def project_unfollow!(project)
project_relationships.find_by_projectuser_id(project.id).destroy
end
project_relationships_controller.rb
class ProjectRelationshipsController < ApplicationController
def create
#project = Project.find(params[:project_relationship][:projectuser_id])
current_user.follow_project!(#project)
redirect_to #project
end
def destroy
#project = ProjectRelationship.find(params[:id]).followed_project
current_user.project_unfollow!(#project)
redirect_to #project
end
end
projects/show.html.erb
<%= render 'follow_form' if signed_in? %>
projects/_follow_form.html.erb
<% if current_user.following_project?(#project) %>
<%= render 'unfollow' %>
<% else %>
<%= render 'follow' %>
<% end %>
projects/_follow.html.erb
<%= form_for(current_user.project_relationships.build(projectuser_id: #project.id)) do |f| %>
<div><%= f.hidden_field :projectuser_id %></div>
<%= f.submit "Follow", class: "btn btn-large btn-primary" %>
<% end %>
projects/_unfollow.html.erb
<%= form_for(current_user.project_relationships.find_by_projectuser_id(#project),
html: { method: :delete }) do |f| %>
<%= f.submit "Unfollow", class: "btn btn-large" %>
<% end %>
First of all - if you run projectfollow!(project) and projectunfollow!(project) in your console (with a user, project etc) do they work properly?
For your forms try the following instead and see if it works:
<%= form_for(current_user.project_relationships.build, url: project_relationships_path(project_id: #project.id)) do |f| %>
Then in your project relationships controller:
class ProjectRelationshipsController < ApplicationController
def create
#project = Project.find(params[:project_id])
current_user.projectfollow!(#project)
redirect_to #project
end
end
So if your create URL is /project_relationships (via POST), the above should post to /project_relationships?project_id=5 and then the controller can find that project.
Also, try to rename your methods so they make sense:
def following_project?(project)
end
def follow_project!(project)
end
def unfollow_project!(project)
end
Now current_user.following_project?(project) makes a lot of sense!
Update
Ok, I think the following is the problem, in your create action you're getting the id from the params:
#project = Project.find(params[:project_relationship][:projectuser_id])
However in your form you're not setting the value of the hidden field:
<%= f.hidden_field :projectuser_id %>
Change it to the following and see if it works:
<%= f.hidden_field :projectuser_id, value: #project.id %> # or wherever the id is from
The problem was that my follow/unfollow form was embedded in another form which caused the error. Once taken out, worked!

Resources