Many to Many table collection_select error - many-to-many

I am trying to have rails populate an inbetween table. The inbetween table is: room_task
The form I am using is the new task form, which is nested.
Here is the model:
class Property < ActiveRecord::Base (property is parent nest)
attr_accessible :brand_id, :name, :user_property_code, :total_rooms, :property_addresses_attributes
belongs_to :brand
has_many :rooms
has_many :nonrooms
end
class Room < ActiveRecord::Base (room)
attr_accessible :number, :out_of_order, :property_id, :room_type_id, :taskable_id
belongs_to :room_type
belongs_to :property
has_many :room_tasks
has_many :tasks, through: :room_tasks
accepts_nested_attributes_for :tasks
accepts_nested_attributes_for :room_tasks
#add_index :room, :property_id
end
class Room < ActiveRecord::Base (task)
attr_accessible :number, :out_of_order, :property_id, :room_type_id, :taskable_id
belongs_to :room_type
belongs_to :property
has_many :room_tasks
has_many :tasks, through: :room_tasks
accepts_nested_attributes_for :tasks
accepts_nested_attributes_for :room_tasks
#add_index :room, :property_id
end
class RoomTask < ActiveRecord::Base (in between table)
attr_accessible :room_id, :task_id
has_one :room
has_one :task
belongs_to :room # foreign key - room id
belongs_to :task # foreign key - task id
end
Controller (task - where I want to create the new task and also the required relationship in the inbetween table)
class TasksController < ApplicationController
before_filter :find_property
def find_property
#property = Property.find(params[:property_id])
#room = #property.rooms
end
# GET /tasks
# GET /tasks.json
def index
#tasks = Task.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #tasks }
end
end
# GET /tasks/1
# GET /tasks/1.json
def show
#task = Task.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #task }
end
end
# GET /tasks/new
# GET /tasks/new.json
def new
#task = Task.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #task }
end
end
# GET /tasks/1/edit
def edit
#task = Task.find(params[:id])
end
# POST /tasks
# POST /tasks.json
def create
#task = Task.new(params[:task])
#task.time_assigned = Time.now
respond_to do |format|
if #task.save
format.html { redirect_to property_tasks_path(#property), notice: 'Task was successfully created.' }
format.json { render json: #task, status: :created, location: #task }
else
format.html { render action: "new" }
format.json { render json: #task.errors, status: :unprocessable_entity }
end
end
end
# PUT /tasks/1
# PUT /tasks/1.json
def update
#task = Task.find(params[:id])
respond_to do |format|
if #task.update_attributes(params[:task])
format.html { redirect_to #task, notice: 'Task was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #task.errors, status: :unprocessable_entity }
end
end
end
# DELETE /tasks/1
# DELETE /tasks/1.json
def destroy
#task = Task.find(params[:id])
#task.destroy
respond_to do |format|
format.html { redirect_to tasks_url }
format.json { head :no_content }
end
end
end
Form (using a collection select (purpose would be to select the room of the property that the task is tied to and populate in the inbetween table)
<%= form_for([#property, #task]) do |f| %>
<% if #task.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#task.errors.count, "error") %> prohibited this task from being saved:</h2>
<ul>
<% #task.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div>
<%= fields_for(:room_task) do |t| %>
<%= collection_select(:room_task, :room_id, #room, :id, :number) %> #without t. works but does not assign
<% end %>
<%= #room %> #debug collection pull - good
<div class="actions">
<%= f.submit %>
</div>
<% end %>
So I need help on ensuring that my inbetween table is populated when selecting the room. When f. or t. is prefixed to the collection_select, rails throws errors.
I am extremely confused. Help would be greatly appreciated, please let me know if any additional information is needed.
receiving this error when adding f. or t.
undefined method `merge' for :number:Symbol
displays and works fine without f. or t. but does not populate table.

Related

Rails, drop down list for increase items quantity in the cart

I'm a beginner in ROR, and I' m building an online shop, and I'm trying to do a drop down list to increase quantity of products to add in the cart at the same time.
I did a form for, linked with the controller, but I don't know why it do not work at all, It shows the form, but It always add elements one by one to the cart. I can choose a quantity in my list, But it is not recognized and add one element when I click on the "add" button
Here is my shop view :
<div class="popup-price-and-add">
<span class="popup-price"><%=number_to_currency(product.price)%></span><br/>
<%= text_field_tag 'quantity' %>
<%= form_for(line_items_path(:set_quantity)) do |form|%>
<p>
<%= form.label :quantity%>
<%= form.select :quantity, (1..10) %>
<p>
<% end %>
<%= link_to image_tag("/elem/Btn-add.png", :class =>"popup-add"), line_items_path(product_id: product), remote: true, :method => :post, :class => "popup-add" %>
</div>
and here is my line_items_controller:
class LineItemsController < ApplicationController
skip_before_action :authorize, only: [:create, :destroy]
include CurrentCart
before_action :set_cart, only: [:create]
before_action :set_line_item, only: [:show, :edit, :update, :destroy]
# GET /line_items
# GET /line_items.json
def index
#line_items = LineItem.all
end
# GET /line_items/1
# GET /line_items/1.json
def show
end
# GET /line_items/new
def new
#line_item = LineItem.new
end
# GET /line_items/1/edit
def edit
end
# POST /line_items
# POST /line_items.json
def create
session[:counter] = 0
quantity = params[:quantity]
product = Product.find(params[:product_id])
#line_item = #cart.add_product(product.id)
respond_to do |format|
if #line_item.save
format.html { redirect_to #line_item.cart, notice: 'Line item was successfully created.' }
format.json { render action: 'show', status: :created, location: #line_item }
else
format.html { render action: 'new' }
format.json { render json: #line_item.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /line_items/1
# PATCH/PUT /line_items/1.json
def update
respond_to do |format|
if #line_item.update(line_item_params)
format.html { redirect_to #line_item, notice: 'Line item was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #line_item.errors, status: :unprocessable_entity }
end
end
end
# DELETE /line_items/1
# DELETE /line_items/1.json
def destroy
#line_item = LineItem.find(params[:id])
#line_item.destroy
respond_to do |format|
if current_cart.line_items.empty?
format.html{redirect_to(store_url, :notice=>'Your cart is empty')}
else
format.html { redirect_to(#line_item.cart, :notice=> 'Item has been removed from your cart.') }
end
format.xml { head :ok}
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_line_item
#line_item = LineItem.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def line_item_params
params.require(:line_item).permit(:product_id)
params.require(:line_item).permit(:quantity)
end
end
as you see, in my create method, I defined a quantity and I permitted it with : params.require(:line_item).permit(:quantity).
Hope It will help you to help me!
Thanks.
You should make a database table for the Items with a column of quantity but if you already have a Items model but without the quantity value you can do this
rails g migration AddQuantityToItems quantity:integer
Rake db:migrate
then you need to do something like this in the view:
<%= form_for(Item) do |f| %>
<%= f.hidden_field :quantity, class: 'cart_quantity' %>
<p class="cart_quantity"></p>
<button class='quantity_down'></button>
<button class='quantity_up'></button>
<%= f.submit 'Add to cart' %>
<% end %>
jQuery
var quantity = 0;
$(document).on('click', 'quantity_down', function() {
quantity -= 1
$('cart_quantity').text(quantity);
$('cart_quantity').val(quantity);
});
$(document).on('click', 'quantity_up', function() {
quantity += 1;
$('cart_quantity').text(quantity);
$('cart_quantity').val(quantity);
});
If you really specifically need a drop down list, thats also possible just switch the buttons with a select dropdown and change the jQuery accordingly.
This is just to give you an idea, i don't know your code so you have to work around this.

NoMethodError in CommentsController#new undefined method `text' for #<Comment id: nil, author: nil, created_at: nil, updated_at: nil>

I'm trying to use rails with react, just by adding a comments section to the app i'm working on. The /comments page works. But when I try to make a new comment. I get this error. I went back to the guide I'm using and doesn't explain anything about this. I'm new to rails and react so if someone could help me out I would appreciate it.
Application Trace:
app/views/comments/_form.html.erb:20:in `block in_app_views_comments__form_html_erb__930297241_104622300'
app/views/comments/_form.html.erb:1:in `_app_views_comments__form_html_erb__930297241_104622300'
app/views/comments/new.html.erb:3:in `_app_views_comments_new_html_erb__151456299_104688260'
comments_controller.rb:
class CommentsController < ApplicationController
before_action :set_comment, only: [:show, :edit, :update, :destroy]
# GET /comments
# GET /comments.json
def index
#comments = Comment.all
end
# GET /comments/1
# GET /comments/1.json
def show
end
# GET /comments/new
def new
#comment = Comment.new
end
# GET /comments/1/edit
def edit
end
# POST /comments
# POST /comments.json
def create
#comment = Comment.new(comment_params)
respond_to do |format|
if #comment.save
format.html { redirect_to #comment, notice: 'Comment was successfully created.' }
format.json { render :show, status: :created, location: #comment }
else
format.html { render :new }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /comments/1
# PATCH/PUT /comments/1.json
def update
respond_to do |format|
if #comment.update(comment_params)
format.html { redirect_to #comment, notice: 'Comment was successfully updated.' }
format.json { render :show, status: :ok, location: #comment }
else
format.html { render :edit }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
end
# DELETE /comments/1
# DELETE /comments/1.json
def destroy
#comment.destroy
respond_to do |format|
format.html { redirect_to comments_url, notice: 'Comment was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_comment
#comment = Comment.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def comment_params
params.require(:comment).permit(:author, :comment_text)
end
end
_form.html.erb:
<%= form_for(#comment) do |f| %>
<% if #comment.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#comment.errors.count, "error") %> prohibited this comment from being saved:</h2>
<ul>
<% #comment.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :author %><br>
<%= f.text_field :author %>
</div>
<div class="field">
<%= f.label :comment_text %><br>
<%= f.text_area :comment_text %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
new.html.erb:
<h1>New Comment</h1>
<%= render 'form' %>
<%= link_to 'Back', comments_path %>
[timestamp]_create_comments.rb:
class CreateComments < ActiveRecord::Migration
def change
create_table :comments do |t|
t.string :author
t.text :comment_text
t.timestamps null: false
end
end
end
Seems like the problem originates with your schema/migration. The line:
params.require(:comment).permit(:author, :text)
suggests that you have a column named text, which is a datatype in Rails. You should pick a name like "comment_text" for that column that doesn't echo the name of a datatype.
It's also possible that you transposed the datatype and the column name in your migration.

Rails 4.1: Unable to create multiple answers in form

Want to create a polling app that allows you to create a question with 5 different possible answers (multiple choice).
The user can create a question via the question_form.html.erb followed by possible answers but it only shows me one box , not five.
question_form.html.erb
<%= form_for([ #poll, #question ]) do |f| %>
<% if #question.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#question.errors.count, "error") %> prohibited this question from being saved:</h2>
<ul>
<% #question.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="form-group">
<%= f.label :title %>
<%= f.text_field :title, class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :kind %><br>
<% #kind_options.each do |option| %>
<label>
<%= f.radio_button :kind, option[1] %>
<%= option[0] %>
</label>
<% end %>
<p>Specify some choices:</p>
<%= f.fields_for :possible_answers do |c| %>
<p>
<%= c.text_field :title, placeholder: "Type your choice", class: "form-control" %>
</p>
<% end %>
</div>
in my questions controller I have added line 5.times { #question.possible_answers.build }
but when i run the program it gives me 1 box to enter the answer not 5?
<div class="actions">
<%= f.submit 'Save', class: "btn btn-primary" %>
</div>
<% end %>
class QuestionsController < ApplicationController
before_action :set_question, only: [:show, :edit, :update, :destroy]
before_action :set_poll
before_action :set_kind_questions
# GET /questions
# GET /questions.json
def index
#questions = Question.all
end
# GET /questions/1
# GET /questions/1.json
def show
end
**# GET /questions/new
def new
#question = #poll.questions.build
5.times { #question.possible_answers.build }
end**
# GET /questions/1/edit
def edit
end
# POST /questions
# POST /questions.json
def create
#question = #poll.questions.build(question_params)
respond_to do |format|
if #question.save
format.html { redirect_to #poll, notice: 'Question was successfully created.' }
format.json { render :show, status: :created, location: #question }
else
format.html { render :new }
format.json { render json: #question.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /questions/1
# PATCH/PUT /questions/1.json
def update
respond_to do |format|
if #question.update(question_params)
format.html { redirect_to #question, notice: 'Question was successfully updated.' }
format.json { render :show, status: :ok, location: #question }
else
format.html { render :edit }
format.json { render json: #question.errors, status: :unprocessable_entity }
end
end
end
# DELETE /questions/1
# DELETE /questions/1.json
def destroy
#question.destroy
respond_to do |format|
format.html { redirect_to questions_url, notice: 'Question was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_question
#question = Question.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def question_params
params.require(:question).permit(:title, :kind, :poll_id)
end
**def set_kind_questions
#kind_options = [
[ "Open Answer", "open" ],
[ "Multiple Choice", "choice" ],
]
end**
def set_poll
#poll = Poll.find params[:poll_id] #/polls/1/questions
end
end
If you're working through Build a Polling Application with Rails, the Question model you're most likely using (which you didn't list) is incomplete, so Rails chokes on possible_answers before the controller's Questions#new iterates through the build method. You need to add accepts_nested_attributes_for :possible_answers to the model. Then 5.times { #question.possible_answers.build } will work.
app/models/question.rb
class Question < ActiveRecord::Base
belongs_to :poll
has_many :possible_answers
accepts_nested_attributes_for :possible_answers
end
I've run into a few snags where the author edited code out of sync with his screencasts. You have to look carefully at the diffs on his tut's repo.

Get count of likes on a post in Rails

In my rails application, I am using the gem, socialization.
I just can't figure out how to display the amount of likes!
My post controller :
class PostsController < ApplicationController
# GET /posts
# GET /posts.json
def index
#posts = Post.all(:order => "created_at DESC")
#posts_not_signed_in = Post.all(:order => "created_at DESC")
#post = Post.new
#users = User.all(:order => "created_at DESC")
respond_to do |format|
format.html # index.html.erb
format.json { render json: #posts }
end
end
def like
post.liked_by current_user
redirect_to root_path
end
# GET /posts/1
# GET /posts/1.json
def show
redirect_to posts_path
end
# GET /posts/new
# GET /posts/new.json
def new
#post = Post.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #post }
end
end
# GET /posts/1/edit
def edit
#post = Post.find(params[:id])
end
# POST /posts
# POST /posts.json
def create
#post = current_user.posts.build(params[:post])
respond_to do |format|
if #post.save
format.html { redirect_to #post, notice: 'Post was successfully created.' }
format.json { render json: #post, status: :created, location: #post }
else
format.html { render action: "new" }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
# PUT /posts/1
# PUT /posts/1.json
def update
#post = Post.find(params[:id])
respond_to do |format|
if #post.update_attributes(params[:post])
format.html { redirect_to #post, notice: 'Post was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
# DELETE /posts/1
# DELETE /posts/1.json
def destroy
#post = Post.find(params[:id])
#post.destroy
respond_to do |format|
format.html { redirect_to posts_url }
format.json { head :no_content }
end
end
end
My user controller :
class UsersController < ApplicationController
def index
#users = User.all
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #users }
end
end
def show
#user = User.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #user }
end
end
def follow
#user = User.find(params[:id])
current_user.toggle_follow!(params[:id])
redirect_to root_path
end
def unfollow
#user = User.find(params[:id])
current_user.stop_following(#user)
redirect_to root_path
end
end
My post model :
class Post < ActiveRecord::Base
attr_accessible :status, :author, :username, :id, :user_id, :user, :website, :bio, :skype, :dob, :age, :email, :motto, :follower, :followable, :votes
belongs_to :user
has_many :like
has_many :likes
validates :status, :presence => true
acts_as_likeable
acts_as_votable
end
My user model :
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable,
# :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me, :username, :user_id, :id, :website, :bio, :skype, :dob, :age, :motto, :follower, :followable
has_many :posts
acts_as_liker
# attr_accessible :title, :body
end
My view :
<% if user_signed_in? %>
<h1 id="welcome" class="nuvo">Welcome <%= current_user.username %>!</h1>
<% else %>
<h1 id="welcome" class="nuvo">Log-In to make some posts!</h1>
<% end%>
<div class="follow-row">
<div class="titan-users nuvo"><h2>BoomIt Users</h2></div>
<div class="user-row nuvo"><%= link_to 'coreypizzle', user_path(1) %> - <%= link_to 'BoomBoard', dashboard_path(1) %></div>
<% #users.each do |user| %>
<div class="user-row nuvo"><%= link_to user.username, user_path(user.id) %> - <%= link_to 'BoomBoard', dashboard_path(user.id) %></div>
<% end %>
</div>
<div class="statuses">
<% if user_signed_in? %><div class="status-form"><%= render 'form' %></div><% end %>
<% if user_signed_in? %>
<% #posts.each do |post| %>
<div class="post">
<div class="tstamp">
<%= image_tag avatar_url_small(post.user), :class => 'gravatar' %>
<strong>Posted <%= time_ago_in_words(post.created_at) %> ago by <%= post.user.username %></strong>
</div>
<div class="status"><%= post.status %></div>
<div class="likearea"><%= link_to 'BoomThis', 'posts/like', :class => 'wtxt nuvo' %> - <%= #post.likes.size %></div>
</div>
<% end %>
<% else %>
<% #posts_not_signed_in.each do |post| %>
<div class="post">
<div class="tstamp">
<%= image_tag avatar_url_small(post.user), :class => 'gravatar' %>
<strong>Posted <%= time_ago_in_words(post.created_at) %> ago by <%= post.user.username %></strong>
</div>
<div class="status"><%= post.status %></div>
</div>
<% end %>
<% end %>
</div>
Any help would be greatly appreciated!
First
has_many :like
has_many :likes
I think you mean just
has_many :likes
So you would do
#likes_num = #post.likes.count
Which will create a query for the number of likes, and not the actually likes themselves.
Old question, but i couldn't find this either.
The correct method call appears to be:
post.likers(User).count
I'm still unsure why you have to pass the model name in, perhaps so you can ask for the number of likes from that class of liker?
This works though.

Undefined method name for nil:NilClass

I am having this problem for too long now and I can't find out where is the problem, so:
Showing /home/alex/Desktop/personal/app/views/entries/list.html.erb where line #17 raised:
undefined method `name' for nil:NilClass
Extracted source (around line #17):
14: <% #entries.each do |entry| %>
15: <tr>
16: <td><%= link_to entry.title, :action => "show", :id => entry.id %></td>
17: <td><%= link_to entry.category.name, :action => "list", :category_id => entry.category.id %></td>
18: </tr>
19: <% end %>
20:
My views/entries/list.html.erb looks looks like this:
<html>
<head>
<title>All Entries</title>
</head>
<body>
<h1>Online Personal Collection- All Entries</h1>
<table border="1">
<tr>
<td width="80%"><p align="center"><i><b>Entry</b></i></td>
<td width="20%"><p align="center"><i><b>Category</b></i></td>
</tr>
<% #entries.each do |entry| %>
<tr>
<td><%= link_to entry.title, :action => "show", :id => entry.id %></td>
<td><%= link_to entry.category.name, :action => "list", :category_id => entry.category.id %></td>
</tr>
<% end %>
</table>
<p><%= link_to "Create new entry", :action => "new" %></p>
<br />
<%=link_to "Back to Index", entries_path%>
<br />
<%=link_to "Back to Account Info", my_account_path%>
<br />
<h3>Enter keyword</h3>
<form action ="search" method="post">
<input name = "key" type="input" />
<input value="Send" type="submit"/>
</form>
</body>
</html>
The models are like this:
class Entry < ActiveRecord::Base
attr_accessible :comments, :date, :description, :title, :category_id, :category_name
belongs_to :category
after_create do |entry|
logger.info "entry created: #{entry.title} #{entry.description}"
end
end
class Category < ActiveRecord::Base
attr_accessible :name
has_many :entries
end
And the entries_controller :
class EntriesController < ApplicationController
# GET /entries
# GET /entries.json
def index
#entries = Entry.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #entries }
end
end
def list
if params[ :category_id].nil?
#entries = Entry.find(:all)
else
#entries = Entry.find(:all ,
:conditions => ["category_id = ?" , params[ :category_id]])
params[ :category_id] = nil
respond_to do |format|
format.html # list.html.erb
format.json { render json: #entry }
end
end
end
# GET /entries/1
# GET /entries/1.json
def show
#entry = Entry.find(params[:id])
#category = Category.find(:all)
respond_to do |format|
format.html # show.html.erb
format.json { render json: #entry }
end
end
# GET /entries/new
# GET /entries/new.json
def new
#entry = Entry.new
#categories= Category.find(:all)
respond_to do |format|
format.html # new.html.erb
format.json { render json: #entry }
end
end
# GET /entries/1/edit
def edit
#entry = Entry.find(params[:id])
#categories = Category.find(:all)
end
# POST /entries
# POST /entries.json
def create
#entry = Entry.new(params[:entry])
respond_to do |format|
if #entry.save
format.html { redirect_to #entry, notice: 'Entry was successfully created.' }
format.json { render json: #entry, status: :created, location: #entry }
else
format.html { render action: "new" }
format.json { render json: #entry.errors, status: :unprocessable_entity }
end
end
end
# PUT /entries/1
# PUT /entries/1.json
Now if someone spot the problem and could help me understand where I'm doing wrong I will be grateful.
Thanks!
Alex.
You have an entry without a category, so entry.category is nil, so entry.category.name (in this instance) is nil.name, which makes no sense. It's generally good practice to avoid chaining methods on associations like this because of this very issue.
Rails has built-in delegation that you could use to prevent this:
class Entry < ActiveRecord::Base
#...
delegate :name, to: :category, prefix: :category, allow_nil: true
end
This defines the entry.category_name instance method. In your view, if no category exists for that entry, nothing would appear there. You can read more about the delegation methods and options here.
UPDATE:
So I ignored the fact that you're trying to link to a nil object, when probably what you really want to do is not display the link at all when the object is nil. There's a link_to_if method (that I've never used, but would probably work for you):
<%= link_to_if(entry.category, entry.category_name, :action => "list", :category_id => entry.category.id %>
You still need to use the category_name delegate method, because the name is printed (without the link) when the first argument evaluates to false.