Rails model as_json overwriting default values - ruby-on-rails

I'm trying overwrite default model values for json but instead of overwriting it create duplicate hash
My model:
class HomeScreenButton < ActiveRecord::Base
belongs_to :product_category
validates :product_category_id, :x, :y, :presence => true
attr_accessible :product_category_id, :x, :y
def as_json(options={})
hash = super(options)
hash.merge({
:product_category_id => "fdfd"
})
end
end
My controller:
def index
#home_screen_buttons = HomeScreenButton.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #home_screen_buttons}
end
end
When I'm opening json it shows me duplicate for product_category_id: [{"created_at":"2013-03-17T11:14:32Z","id":1,"product_category_id":5,"updated_at":"2013-03-17T11:14:32Z","x":300,"y":200,"product_category_id":"dfdffff"}]

There is no need to merge hashes
def as_json(options={})
hash = super(options)
hash[:product_category_id] = "fdfd"
hash
end

Related

Need help validating query parameters

I have multiple methods within my controller that takes in query parameters. How can I validate that I am being passed in valid parameters? For example, for the index method, how can I make sure that I am getting an array of authorIds.
def index
author_ids_array = params[:authorIds].to_s.split(',')
posts = Post
.get_posts_by_user_id(author_ids_array)
.order(sort_column => sort_direction)
if posts
render json: { posts: posts }, status: :ok
else
render json: {error: posts.errors}, status: :unprocessable_entity
end
end
Or in this update method. How can I validate that I am getting a valid postId
def update
post = current_user.posts.find_by(id: params[:id])
if post.update!(post_params)
post_hash = post.as_json
post_hash.merge!(authorIds: params[:authorIds])
render json: {post: post_hash}, status: :ok
else
render json: {error: post.errors}, status: :unprocessable_entity
end
end
Update:
Post Model:
class Post < ApplicationRecord
# Associations
has_many :user_posts
has_many :users, through: :user_posts, dependent: :destroy
# Validations
validates :text, presence: true, length: { minimum: 3 }
validates :popularity, inclusion: { in: 0.0..1.0 }
def tags
if super
super.split(",")
end
end
def tags=(value)
if value.kind_of? Array
super value.join(",")
else
super value
end
end
def self.get_posts_by_user_id(user_id)
Post.joins(:user_posts).where(user_posts: { user_id: user_id })
end
end
User Model:
class User < ApplicationRecord
has_secure_password
# Associations
has_many :user_posts
has_many :posts, through: :user_posts, dependent: :destroy
# Validations
validates :username, :password, presence: true
validates :password, length: { minimum: 6 }
validates :username, uniqueness: true
end
User_post Model:
class UserPost < ApplicationRecord
belongs_to :user
belongs_to :post
end
You can use specific render like below user this in any method like
def index
return render body: params.inspect
.
.
end
user below code
return render body: params.inspect
so when you use index it will give you params which is passing
OR you can user below code in your application.html.erb above <%= yield%>
<%= debug(params) if Rails.env.development? %>
After your clarifications, your question remains unclear to me and it is difficult to guess what you're doing. But I understood that you want to ensure that params[:authorIds] or anything else is an array.
You can see if a given variable is an array the following way:
a = ["1","2"]
if a.is_a?(Array)
puts "is an array"
end
With params: params[:authorIds].is_a?(Array)
You can use byebug (before Rails 7) or debugger (for Rails 7) to inspect what a param is. As an example:
(ruby#whatever: cluster worker 1: 42779 [MyApp]#42793) params[:ids].class
Array

Rails Paperclip Attachment not saving because polymorphic id not assigned

I am brand new here. I have been fighting with a rails app for hours now and need an answer. I have searched and tried many suggestions related to what I am trying to accomplish, but to no avail. I got the paperclip gem running for my rails app yesterday, and it was a breeze to add an attachment to a single model. However, I defined an agnostic, polymorphic attachments table to hold attached files for all models that need this functionality.
My issue is that I cannot get the attached file to save through nested parameters. All my parameters are accepted, but the db rolls back and doesn't save (using guard). Message is: 'attachments.attachable_id'=>'can't be blank'. I need this to be the foreign key of the related table, and this has to be saved along with the attachment_type. Here's what I have:
class ReportsController < ApplicationController
def new
#report = Report.new
#report.attachments.build(attachable_id: #report.id)
end
def create
#report = Report.new(params)
#report.attachments.build
respond_to do |format|
if #report.save
format.html { redirect_to #report, notice: 'Report was successfully created.' }
format.json { render json: #report, status: :created, location: #report }
else
format.html { render action: "new" }
format.json { render json: #report.errors, status: :unprocessable_entity }
end
end
end
private
def report_params
params.require(:report).permit(:filing_year, :filing_number, :order_number, :location, :environmental_review,:biological_review, :cultural_review, :date_received, :status, attachments_attributes: [:id, :attachable_id, :attachable_type, :attachment])
end
end
And for the models:
class Attachment < ActiveRecord::Base
belongs_to :attachable, polymorphic: true
validates :attachable_id, :attachable_type, presence: true
do_not_validate_attachment_file_type :attachment
Paperclip.interpolates :attached_to do |attachment, style|
attachment.instance.attachable.class.to_s.downcase
end
has_attached_file :attachment,
:url => "/attachments/:id/:basename.:extension",
:path => ":rails_root/public/attachments/:attached_to/:id/:basename.:extension",
:default_url => "/attachments/original/no-file.txt"
end
class Report < ActiveRecord::Base
has_one :environmental_review
has_many :attachments, as: :attachable
accepts_nested_attributes_for :attachments
validates :order_number, presence: true
.
.
.
end
And view (in slim):
.report
= form_for #report do |f|
.
.
.
= f.fields_for :attachments do |a|
= a.file_field :attachment
.
.
.
Thank you.
Well for one in your create method you call #reports.attachments.build again, but don't set the assignable_id, you need to do that. The other thing you can do is add a hidden form field that has the name attachable_id.

Ruby On Rails Pagination and delete :through association

I am running into a strange situation, considering the following models:
class Collection < ActiveRecord::Base
attr_accessible :name, :season, :year
has_many :collection_items_assocs
has_many :items, :through => :collection_items_assocs
end
class Item < ActiveRecord::Base
attr_accessible :name, :reference, :item_type_id
has_many :pictures
has_one :item_type
end
class CollectionItemsAssoc < ActiveRecord::Base
attr_accessible :collection_id, :item_id
belongs_to :item
belongs_to :collection
end
I can successfully retrieve Items associated to a Collection with the following code:
# GET /collections/1
# GET /collections/1.json
def show
#collection = Collection.find(params[:id])
#collection.items = Collection.find(params[:id]).items
respond_to do |format|
format.json { render json: #collection.to_json(:include => {:items => #collection}) }
end
end
But when I try to include pagination (for items) like that
# GET /collections/1
# GET /collections/1.json
def show
#collection = Collection.find(params[:id])
**#collection.items = Collection.find(params[:id]).items.paginate(:page => params[:page],:per_page =>1)**
respond_to do |format|
format.json { render json: #collection.to_json(:include => {:items => #collection}) }
end
end
It works for the following call
/retailapp/collections/1?format=json&**page=1**
Then if I call
/retailapp/collections/1?format=json&**page=2**
the records in the association table CollectionItemsAssoc are deleted
I really don't get it
Thanks for your help
The problem is the code to fetch the items
#collection.items = Collection.find(params[:id]).items
it assigned the fetched items to current collection object.
you need to change the response to support the pagination on associate objects
  def show
   #collection = Collection.find(params[:id])
respond_to do |format|
format.json {
json_hash = #collection.as_json
json_hash[:items] = #collection.items.paginate(:page => params[:page],:per_page =>1).as_json
render json: json_hash.to_json
}
end
Additionally you can overwrite to_json method inside Collection model.

Hiding Rails Model Attributes

I have a controller for an API that looks like this:
def index
respond_to do |format|
format.json { render :json => #groups.to_json(:only => [:id, :name, :description, :created_at, :updated_at])}
end
end
def show
respond_to do |format|
format.json { render :json => #group.to_json(:only => [:id, :name, :description, :created_at, :updated_at]) }
end
end
# #todo add store to item
def create
if #group.save
render :json => #group.to_json(:only => [:id, :name, :description, :created_at, :updated_at])
else
render :status => 406
end
end
def update
if #group.update_attributes(params[:group])
render :json => #group.to_json(:only => [:id, :name, :description, :created_at, :updated_at])
else
render :status => 406
end
end
def destroy
#group.destroy
render :text => ""
end
As you can see, I'm repeating my self a lot. I'd love to make these (and only these) attributes available by way of the model, but couldn't find a fitting solution. Is there anything to protect attributes from mass writing? Or do I possibly mean mass reading?
As noted in comments below I want to have a model with attributes, name and i_am_private. When I render that model as json - render :json => #model - I want only name to show up.
Ruby 1.8.7
Rails 3
How about overriding as_json method in your Group model?
class Group < ActiveRecord:Base
...
def as_json(options={})
{
:id => id,
:name => name,
:description => description,
:created_at => created_at,
:updated_at => updated_at
}
end
end
To prevent mass assignment, add the following to your model:
attr_accessible :attr1, :attr2, :attr3
where attr1, attr2, attr3 and so on are the attributes you want to allow for mass assignment, the rest of the attributes for that model will not be allowed for mass assignment.

Rails many to many token fields help

I am having that problem that my model dont want to save. I have a token field input for tags.
I have followed this guide for the token input: http://railscasts.com/episodes/258-token-fields
I get this error when I try to create a new konkurrancer:
NoMethodError in Admin/konkurrancersController#create
undefined method `class_name' for nil:NilClass
Rails.root: C:/Rails/konkurranceportalen
Application Trace | Framework Trace | Full Trace
app/models/konkurrancer.rb:15:in `tag_tokens='
app/controllers/admin/konkurrancers_controller.rb:48:in `new'
app/controllers/admin/konkurrancers_controller.rb:48:in `create'
http://pastie.org/1834194
Request
Parameters:
{"utf8"=>"✓",
"authenticity_token"=>"yo7wcAQl81tx3zZpPP44ENPYzYRZLpgyYKY+HK3yFKM=",
"konkurrancer"=>{"name"=>"Vind en rejse",
"banner2"=>"asdasd",
"tracking"=>"sadasd",
"vaerdi"=>"12222",
"tid"=>"1 min",
"tag_tokens"=>"1",
"bedom"=>"2",
"kategori_id"=>"9",
"form"=>"Nyhedsbrev",
"partner"=>"Iqmedier",
"udtraekkes(3i)"=>"30",
"udtraekkes(2i)"=>"4",
"udtraekkes(1i)"=>"2011",
"udtraekkes(4i)"=>"08",
"udtraekkes(5i)"=>"26",
"arrangeor"=>"",
"note"=>""},
"commit"=>"Opret konkurrence"}
My konkurrancer model:
class Konkurrancer < ActiveRecord::Base
attr_accessible :name, :tag_tokens
has_many :tagsmenus
has_many :tags, :through => :tagsmenus
attr_reader :tag_tokens
def tag_tokens=(ids)
self.tag_ids = ids.split(",")
end
end
My tag model:
class Tag < ActiveRecord::Base
has_many :tagsmenus
has_many :konkurrancers, :through => :tagsmenus
has_friendly_id :name, :use_slug => true
before_save :assign_cached_slug, :unless => :cached_slug?
protected
def assign_cached_slug
self.cached_slug = self.name.gsub(/\s+/, '_').gsub(/[^\w\-]/, '')
end
end
My tagmenu model:
class Tagsmenu < ActiveRecord::Base
end
My controller:
def new
#konkurrancer = Konkurrancer.new
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #konkurrancer }
end
end
# POST /konkurrancers
# POST /konkurrancers.xml
def create
#konkurrancer = Konkurrancer.new(params[:konkurrancer])
respond_to do |format|
if #konkurrancer.save
format.html { redirect_to(:admin_konkurrancers, :notice => 'Konkurrancer was successfully created.') }
format.xml { render :xml => :admin_konkurrancers, :status => :created, :location => #konkurrancer }
else
format.html { render :action => "new" }
format.xml { render :xml => #konkurrancer.errors, :status => :unprocessable_entity }
end
end
end
I have created the join table and the model and also added the relation to my tag model.
Your model has some conflicting statements. You first define:
attr_accessor ... :tag_tokens
then later have:
attr_reader :tag_tokens
which is not necessary given the first line or vice versa given that later you have a deinition for the setter:
def tag_tokens(ids)
self.tag_ids = ids.split(',')
end
I don't see tag_ids defined either given it is not a column in your table. You should probably remove the attr_accessor definition for the tag_tokens and then define the tag_ids method for starters.
class Tagsmenu < ActiveRecord::Base
belongs_to :konkurrancer
belongs_to :tag
end

Resources