I'm trying to create an application where users can freely create shops and associated shop item for a specific shop is displayed when a show action is called but I seem to be doing something wrong. Any help here will be appreciated. I have attached shots of my code below.
class ShopItem < ActiveRecord::Base
belongs_to :shop
def self.find_shop_items_for_sale
find(:all, :order => "title", :conditions => ["shop_id = ?", #shop.id])
end
end
class Shop < ActiveRecord::Base
has_many :shop_items
end
#Controllers
class ShopsController < ApplicationController
def new
#shop = Shop.new
end
def create
#shop = Shop.new(params[:shop])
#shop.user_id = current_user.id
respond_to do |format|
if #shop.save
flash[:notice] = "Successfully created shop."
format.html {redirect_to(all_shops_shops_url)}
format.xml {render :xml => #shop, :status => :created, :location => #shop }
else
format.html {render :action => 'new'}
format.xml { render :xml => #shop.errors, :status => :unprocessable_entity }
end
end
end
def show
#shop = Shop.find(params[:id])
#shop_items = ShopItem.find_shop_items_for_sale
#shop_cart = find_shop_cart
end
class ShopItemsController < ApplicationController
def user
#per_page ||= 5
#user = User.find(params[:id])
#shop_items = ShopItem.find(:all, :conditions=>["user_id = ?", #user.id], :order=>"id desc")
end
def show
#shop_item = ShopItem.find(params[:id])
#shop = #shop_item.shop
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #shop_item }
end
end
# GET /shop_items/new
# GET /shop_items/new.xml
def new
#shop_item = ShopItem.new
#shop = Shop.find(params[:id])
##shop_items = ShopItem.paginate(:all, :condition=>["shop_id] = ?", #shop.id], :order=> "id desc", :page => params[:page],:per_page => #per_page)
#shop_items = ShopItem.find(:all, :conditions=>["shop_id = ?", #shop.id], :order=> "id desc")
#shop_item.shop_id = params[:id]
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #shop_item }
end
end
# GET /shop_items/1/edit
def edit
#shop_item = ShopItem.find(params[:id])
end
# POST /shop_items
# POST /shop_items.xml
def create
#shop_item = ShopItem.new(params[:shop_item])
#shop_item.user_id = current_user.id
respond_to do |format|
if #shop_item.save
flash[:notice] = 'Shop item was successfully created.'
format.html { redirect_to(#shop_item) }
format.xml { render :xml => #shop_item, :status => :created, :location => #shop_item }
else
#shop = Shop.find(#shop_item.shop_id)
##shop_items = ShopItem.paginate(:all, :condition =>["shop_id = ?", #shop.id], :order=> "id desc" , :page => params[:page], :per_page => #per_page)
#shop_items = ShopItem.find(:all, :conditions =>["shop_id = ?", #shop.id], :order=> "id desc")
format.html { render :action => "new" }
format.xml { render :xml => #shop_item.errors, :status => :unprocessable_entity }
end
end
end
If you specify that shop :has_many :shop_items, then you don't have to specify actions like find_shop_items_for_sale. Just call:
#shop = Shop.find(params[:id])
#shop_items = #shop.shop_items
Also trying to retrive all shop items for user (action user) is a bad idea. Instead take a look on will_paginate gem.
On the other side, your question isn't question at all and it would be much easier if you will ask a specific question, or just try to explain what problems you have.
Related
I have a simple has_one relationship setup but I want to add records to Damages table only when the text_field is not blank or nil. Right now it's adding records that are blank or nil to the other table.
My view:
<%= f.fields_for :damage do |builder| %>
<%= builder.label 'Damage' %><br />
<%= builder.text_field :dam_detail %>
<% end %>
Packjob Model:
class Packjob < ActiveRecord::Base
attr_accessible :pj_damage
has_one :damage
accepts_nested_attributes_for :damage
end
Damage Model:
class Damage < ActiveRecord::Base
attr_accessible :dam_detail
belongs_to :packjob
end
How do I allow only non blank or nil values being added?
Is best practice to add logic for this to the helper?
EDIT:
Here's the controller for Packjobs:
class PackjobsController < ApplicationController
# GET /packjobs
# GET /packjobs.json
def index
#packjobs = Packjob.includes(:damage).all
#packers = Packer.find(:all)
#rigs = Rig.find(:all, :order => "rig_type_number")
respond_to do |format|
format.html # index.html.erb
format.json { render json: #packjobs }
end
end
# GET /packjobs/1
# GET /packjobs/1.json
def show
#packjob = Packjob.find(params[:id])
#packers = Packer.find(:all)
respond_to do |format|
format.html # show.html.erb
format.json { render json: #packjob }
end
end
# GET /packjobs/new
# GET /packjobs/new.json
def new
#packjob = Packjob.new
#packers = Packer.find(:all, :conditions => { :p_team => "t" }, :order => "p_name")
#rigs = Rig.find(:all, :conditions => { :rig_status => "t" }, :order => "rig_type_number")
#damage = #packjob.build_damage
##book = #author.build_book
respond_to do |format|
format.html # new.html.erb
format.json { render json: #packjob }
end
end
# GET /packjobs/1/edit
def edit
#packjob = Packjob.find(params[:id])
#packers = Packer.find(:all, :conditions => { :p_team => "t" }, :order => "p_name")
#rigs = Rig.find(:all, :conditions => { :rig_status => "t" }, :order => "rig_type_number")
end
# POST /packjobs
# POST /packjobs.json
def create
#packjob = Packjob.new(params[:packjob])
#packers = Packer.find(:all, :conditions => { :p_team => "t" }, :order => "p_name")
#rigs = Rig.find(:all, :conditions => { :rig_status => "t" }, :order => "rig_type_number")
respond_to do |format|
if #packjob.save
format.html { redirect_to #packjob, notice: 'Packjob was successfully created.' }
format.json { render json: #packjob, status: :created, location: #packjob }
else
format.html { render action: "new" }
format.json { render json: #packjob.errors, status: :unprocessable_entity }
end
end
end
# PUT /packjobs/1
# PUT /packjobs/1.json
def update
#packjob = Packjob.find(params[:id])
#packers = Packer.find(:all, :conditions => { :p_team => "t" }, :order => "p_name")
#rigs = Rig.find(:all, :conditions => { :rig_status => "t" }, :order => "rig_type_number")
respond_to do |format|
if #packjob.update_attributes(params[:packjob])
format.html { redirect_to #packjob, notice: 'Packjob was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #packjob.errors, status: :unprocessable_entity }
end
end
end
# DELETE /packjobs/1
# DELETE /packjobs/1.json
def destroy
#packjob = Packjob.find(params[:id])
#packjob.destroy
respond_to do |format|
format.html { redirect_to packjobs_url }
format.json { head :no_content }
end
end
end
Also the I want the packjob to allow for blanks in damage text_field, I just don't want the records added to the Damages table..
This is a job for validations. Specifically, you want two things:
You want your Damage class to validate that :dam_detail is not blank or nil:
class Damage < ActiveRecord::Base
# ... rest of class here ...
validates :dam_detail, :presence => true, :length => { :minimum => 1 }
end
You want your Packjob class to validate that its contained Damage object is valid:
class Packjob < ActiveRecord::Base
# ... rest of class here ...
validates_associated :damage
end
I also recommend modifying your database schema to add the restriction that the dam_detail field cannot be null. See the migrations guide for more info.
Even though its more commonly used for has_many the cocoon gem https://github.com/nathanvda/cocoon is great for this. That gem will allow you to build the relation on the fly from the front end. it will also allow you to destroy the relation too.
I have an issue, I cant figure out what the problem is with the product controller error,
I will not render the product index view page which is what i want to work.
my code is here as follows :
offers controller
class OffersController < ApplicationController
attr_accessible :product , :reserve_price
def your_offer
#your_offer = Offer.new
end
def new
#offer = Offer.new = :your_offer
end
end
and Products Controller
class ProductsController < ApplicationController
before_filter :authenticate, :except => [:index, :show]
# GET /products
# GET /products.xml
def index
#offer = Offer.new
#products = Product.search(params[:search_query])
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #products }
end
end
# GET /products/1
# GET /products/1.xml
def show
#product = Product.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #product }
end
end
# GET /products/new
# GET /products/new.xml
def new
#product = Product.new
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #product }
end
end
# GET /products/1/edit
def edit
#product = Product.find(params[:id])
end
# POST /products
# POST /products.xml
def create
#product = current_user.products.new(params[:product])
respond_to do |format|
if #product.save
format.html { redirect_to(#product, :notice => 'Product was successfully created.') }
format.xml { render :xml => #product, :status => :created, :location => #product }
else
format.html { render :action => "new" }
format.xml { render :xml => #product.errors, :status => :unprocessable_entity }
end
end
end
# PUT /products/1
# PUT /products/1.xml
def update
#product = Product.find(params[:id])
respond_to do |format|
if #product.update_attributes(params[:product])
format.html { redirect_to(#product, :notice => 'Product was successfully updated.') }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => #product.errors, :status => :unprocessable_entity }
end
end
end
# DELETE /products/1
# DELETE /products/1.xml
def destroy
#product = Product.find(params[:id])
#product.destroy
respond_to do |format|
format.html { redirect_to(products_url) }
format.xml { head :ok }
end
end
end
Offer Model
class Offer < ActiveRecord::Base
belongs_to :product
has_many :reserve_prices
attr_accessible :product, :offer , :reserve_price
validates_presence_of :offer
validate :ensure_meets_reserve_price
private
def ensure_meets_reserve_price
if amount < self.product.reserve_price
errors.add(:amount, "does not meet reserve price")
end
end
private
def reserve_price
product.reserve_price
end
def your_offer
#your_offer = Offer.new
end
def new
#offer = Offer.new = :your_offer
end
end
product index viex snippet
<%= form_for #offer do |f| %>
<%= f.text_field :your_offer %>
<%= f.submit "Make Offer" %>
<% end %>
Could any one see where my eror is ?
Its complaining about #offer = Offer.new
Did you run the migration and restarted the server after creating offers?
Did you declare it as a resource in config/routes.rb as
resources :products, :shallow => true do
resources :offers # or at least just this line
end
Edit:
Get rid of this line and try again
attr_accessible :product, :offer , :reserve_price
is :offer a column in the offers table?
You cannot have columns from another model in attr_accessible.
I'm trying to set the carrier for my new users but when i submit i get this errorr
Carrier(#37295244) expected, got
String(#15496392)
<div class= "field">
<%= f.label :carrier %><br>
<%= f.collection_select(:carrier, Carrier.find(:all) ,:name, :name) %>
</div>
usermodel
class User < ActiveRecord::Base
acts_as_authentic
after_create :set_sub
after_create :set_universal
after_create :set_carrier
def set_sub
#self.roles << "subscriber"
self.roles_mask = 4
end
def set_universal
self.channels << Channel.find(1)
end
def set_carrier
self.carriers<< self.carrier_name
end
ROLES = %w[admin moderator subscriber]
#Each user can subscribe to many channels
has_and_belongs_to_many :channels
#Each user who is a moderator can moderate many channels
#has_many :channel_mods
has_and_belongs_to_many :modifies , :class_name => "Channel"
#Each user can receive many messages
has_and_belongs_to_many :messages
#Each user belongs to a carrier
belongs_to :carrier
#Filter users by role(s)
named_scope :with_role, lambda { |role| {:conditions => "roles_mask & #{2**ROLES.index(role.to_s)} > 0 "} }
def roles
ROLES.reject { |r| ((roles_mask || 0) & 2**ROLES.index(r)).zero? }
end
def roles=(roles)
self.roles_mask = (roles & ROLES).map { |r| 2**ROLES.index(r) }.sum
end
def role_symbols
roles.map do |role|
role.underscore.to_sym # NOT role.name.underscore.to_sym (role is a string)
end
end
end
carrier model
class Carrier < ActiveRecord::Base
has_many :users
end
users controller
class UsersController < ApplicationController
filter_resource_access
# GET /users
# GET /users.xml
def index
#users = User.all
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #users }
end
end
# GET /users/1
# GET /users/1.xml
def show
##user = User.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #user }
end
end
# GET /users/new
# GET /users/new.xml
def new
##user = User.new
#carriers = Carrier.find(:all)
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #user }
end
end
# GET /users/1/edit
def edit
##user = User.find(params[:id])
end
def create
##user = User.new(params[:user])
##user.channels << Channel.find(1)
respond_to do |format|
if #user.save
format.html { redirect_to(:channels, :notice => 'Registration successfully.') }
format.xml { render :xml => #user, :status => :created, :location => #user }
else
format.html { render :action => "new" }
format.xml { render :xml => #user.errors, :status => :unprocessable_entity }
end
end
end
def profile
#user = User.find(params[:id])
end
# PUT /users/1
# PUT /users/1.xml
def update
##user = current_user
respond_to do |format|
if #user.update_attributes(params[:user])
format.html { redirect_to(#user, :notice => 'User was successfully updated.') }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => #user.errors, :status => :unprocessable_entity }
end
end
end
# DELETE /users/1
# DELETE /users/1.xml
def destroy
#user = User.find(params[:id])
#user.destroy
respond_to do |format|
format.html { redirect_to(users_url) }
format.xml { head :ok }
end
end
def delete
#user = User.find(params[:user_id])
#user.destroy
redirect_to :users
end
end
I have not tested your code but at first sight I can see were might be the source of the error:
def set_carrier
self.carriers<< self.carrier_name
end
You assign carrier_name, probably a string to self.carriers which should hold an array of Carrier object.
I"m trying to use a named scope to set my users carrier but keep getting this error
undefined method `target' for #<ActiveRecord::Relation:0x5ee3e40>
app/models/user.rb:19:in `set_carrier'
app/controllers/users_controller.rb:49:in `block in create'
app/controllers/users_controller.rb:48:in `create'
<div class= "field">
<%= f.label :carrier %><br>
<%= f.collection_select(:carrier_name, Carrier.find(:all) ,:name, :name) %>
</div>
user.rb
class User < ActiveRecord::Base
acts_as_authentic
after_create :set_sub
after_create :set_universal
after_create :set_carrier
def set_sub
#self.roles << "subscriber"
self.roles_mask = 4
end
def set_universal
self.channels << Channel.find(1)
end
def set_carrier
#carrier = Carrier.with_name(self.carrier_name)
self.carrier<< #carrier
end
ROLES = %w[admin moderator subscriber]
#Each user can subscribe to many channels
has_and_belongs_to_many :channels
#Each user who is a moderator can moderate many channels
#has_many :channel_mods
has_and_belongs_to_many :modifies , :class_name => "Channel"
#Each user can receive many messages
has_and_belongs_to_many :messages
#Each user belongs to a carrier
belongs_to :carrier
#Filter users by role(s)
named_scope :with_role, lambda { |role| {:conditions => "roles_mask & #{2**ROLES.index(role.to_s)} > 0 "} }
def roles
ROLES.reject { |r| ((roles_mask || 0) & 2**ROLES.index(r)).zero? }
end
def roles=(roles)
self.roles_mask = (roles & ROLES).map { |r| 2**ROLES.index(r) }.sum
end
def role_symbols
roles.map do |role|
role.underscore.to_sym # NOT role.name.underscore.to_sym (role is a string)
end
end
end
carrier.rb
class Carrier < ActiveRecord::Base
has_many :users
named_scope :with_name, lambda {|name| {:conditions => {:name => name}}}
end
user controller
class UsersController < ApplicationController
filter_resource_access
# GET /users
# GET /users.xml
def index
#users = User.all
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #users }
end
end
# GET /users/1
# GET /users/1.xml
def show
##user = User.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #user }
end
end
# GET /users/new
# GET /users/new.xml
def new
##user = User.new
#carriers = Carrier.find(:all)
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #user }
end
end
# GET /users/1/edit
def edit
##user = User.find(params[:id])
end
def create
##user = User.new(params[:user])
##user.channels << Channel.find(1)
respond_to do |format|
if #user.save
format.html { redirect_to(:channels, :notice => 'Registration successfully.') }
format.xml { render :xml => #user, :status => :created, :location => #user }
else
format.html { render :action => "new" }
format.xml { render :xml => #user.errors, :status => :unprocessable_entity }
end
end
end
def profile
#user = User.find(params[:id])
end
# PUT /users/1
# PUT /users/1.xml
def update
##user = current_user
respond_to do |format|
if #user.update_attributes(params[:user])
format.html { redirect_to(#user, :notice => 'User was successfully updated.') }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => #user.errors, :status => :unprocessable_entity }
end
end
end
# DELETE /users/1
# DELETE /users/1.xml
def destroy
#user = User.find(params[:id])
#user.destroy
respond_to do |format|
format.html { redirect_to(users_url) }
format.xml { head :ok }
end
end
def delete
#user = User.find(params[:user_id])
#user.destroy
redirect_to :users
end
end
You might be using an array instead of a singular item. belongs_to relationships are either nil or a model.
You may have intended to do a direct assignment:
def set_carrier
self.carrier = Carrier.with_name(self.carrier_name).first
end
The << operator is used to append items to arrays, but carrier is not an array. This may trip up something deeper in Rails.
Just in case this helps anyone: I was getting this error message too with a model like this:
def Foo
has_many :bars
has_many :thingies, through: :bars
end
I was then doing this in the controller;
Foo.all.includes(:bars, :thingies)
and it blew up trying to go through scopes. The fix was to remove "bars" from the includes call - they will be automatically eager-loaded because "thingies" is being eager loaded.
I have created a blog application using Ruby on Rails and have just added an authentication piece and it is working nicely. I am now trying to go back through my application to adjust the code such that it only shows information that is associated with a certain user.
Currently, Users has_many :posts and Posts has_many :comments.
When a post is created I am successfully inserting the user_id into the post table. Additionally I am successfully only displaying the posts that belong to a certain user upon their login in the /views/posts/index.html.erb view. My problem is with the comments.
For instance on the home page, when logged in, a user will see only posts that they have written, but comments from all users on all posts. Which is not what I want and need some direction in correcting. I want only to display the comments written on all of the logged in users posts.
Do I need to create associations such that comments also belong to user? Or is there a way to adjust my code to simply loop through post to display this data.
I have put the code for the PostsController, CommentsController, and /posts/index.html.erb below and also my view code but will post more if needed.
class PostsController < ApplicationController
before_filter :authenticate
auto_complete_for :tag, :tag_name
auto_complete_for :ugtag, :ugctag_name
def index
#tag_counts = Tag.count(:group => :tag_name,
:order => 'count_all DESC', :limit => 20)
conditions, joins = {}, :votes
#ugtag_counts = Ugtag.count(:group => :ugctag_name,
:order => 'count_all DESC', :limit => 20)
conditions, joins = {}, :votes
#vote_counts = Vote.count(:group => :post_title,
:order => 'count_all DESC', :limit => 20)
conditions, joins = {}, :votes
unless(params[:tag_name] || "").empty?
conditions = ["tags.tag_name = ? ", params[:tag_name]]
joins = [:tags, :votes]
end
#posts= current_user.posts.paginate(
:select => "posts.*, count(*) as vote_total",
:joins => joins,
:conditions=> conditions,
:group => "votes.post_id, posts.id ",
:order => "created_at DESC",
:page => params[:page], :per_page => 5)
#popular_posts=Post.paginate(
:select => "posts.*, count(*) as vote_total",
:joins => joins,
:conditions=> conditions,
:group => "votes.post_id, posts.id",
:order => "vote_total DESC",
:page => params[:page], :per_page => 3)
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #posts }
format.json { render :json => #posts }
format.atom
end
end
def show
#post = Post.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #post }
end
end
def new
#post = Post.new
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #post }
end
end
def edit
#post = Post.find(params[:id])
end
def create
#post = current_user.posts.create(params[:post])
respond_to do |format|
if #post.save
flash[:notice] = 'Post was successfully created.'
format.html { redirect_to(#post) }
format.xml { render :xml => #post, :status => :created, :location => #post }
else
format.html { render :action => "new" }
format.xml { render :xml => #post.errors, :status => :unprocessable_entity }
end
end
end
def update
#post = Post.find(params[:id])
respond_to do |format|
if #post.update_attributes(params[:post])
flash[:notice] = 'Post was successfully updated.'
format.html { redirect_to(#post) }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => #post.errors, :status => :unprocessable_entity }
end
end
end
def destroy
#post = Post.find(params[:id])
#post.destroy
respond_to do |format|
format.html { redirect_to(posts_url) }
format.xml { head :ok }
end
end
end
CommentsController
class CommentsController < ApplicationController
before_filter :authenticate, :except => [:show, :create]
def index
#comments = Comment.find(:all, :include => :post, :order => "created_at DESC").paginate :page => params[:page], :per_page => 5
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #comments }
format.json { render :json => #comments }
format.atom
end
end
def show
#comment = Comment.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #comment }
end
end
# GET /posts/new
# GET /posts/new.xml
# GET /posts/1/edit
def edit
#comment = Comment.find(params[:id])
end
def update
#comment = Comment.find(params[:id])
respond_to do |format|
if #comment.update_attributes(params[:comment])
flash[:notice] = 'Comment was successfully updated.'
format.html { redirect_to(#comment) }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => #comment.errors, :status => :unprocessable_entity }
end
end
end
def create
#post = Post.find(params[:post_id])
#comment = #post.comments.build(params[:comment])
respond_to do |format|
if #comment.save
flash[:notice] = "Thanks for adding this comment"
format.html { redirect_to #post }
format.js
else
flash[:notice] = "Make sure you include your name and a valid email address"
format.html { redirect_to #post }
end
end
end
def destroy
#comment = Comment.find(params[:id])
#comment.destroy
respond_to do |format|
format.html { redirect_to Post.find(params[:post_id]) }
format.js
end
end
end
View Code for Comments
<% Comment.find(:all, :order => 'created_at DESC', :limit => 3).each do |comment| -%>
<div id="side-bar-comments">
<p>
<div class="small"><%=h comment.name %> commented on:</div>
<div class="dark-grey"><%= link_to h(comment.post.title), comment.post %><br/></div>
<i><%=h truncate(comment.body, :length => 100) %></i><br/>
<div class="small"><i> <%= time_ago_in_words(comment.created_at) %> ago</i></div>
</p>
</div>
<% end -%>
I believe you can set up another relation on user model
has_many :comments, :through => :posts
and then user #user.comments.
First, don't mess with MVC. Line:
Comment.find(:all, :order => 'created_at DESC', :limit => 3)
should be in controller:
#comments = Comment.find(:all, :order => 'created_at DESC', :limit => 3)
and in view:
<% #comments.each do |comment| %>
Or even better with partials:
<%= render :partial => "comment_item", :collection => #comments %>
It will iterate over all #comments.
Next, if you want to display all comments assigned to a post, then relation post has_many comments is enough. Use it like this:
# controller
#posts = current_user.posts(:include => :comments)
# view
<% #posts.each do |post| %>
<%=h post.title %> - Comments: <br />
<% post.comments.each do |comment| %>
<%=h comment.body %>
<% end %>
<% end %>
If you want to show only comments posted by current_user then all your comments should have user_id field filled. And use it in the same way as you are showing users posts.