Limit dynamic field with cocoon gem in rails 3 - ruby-on-rails-3

I am using cocoon gem for adding dynamic fields in my webform, now i want to restrict them to add only six fields, how can I do it?
below is the code I am using in my helper:
def link_to_add_association(*args, &block)
if block_given?
f = args[0]
association = args[1]
html_options = args[2] || {}
link_to_add_association(capture(&block), f, association, html_options)
else
name = args[0]
f = args[1]
association = args[2]
html_options = args[3] || {}
html_options[:class] = [html_options[:class], "add_fields"].compact.join(' ')
html_options[:'data-association'] = association.to_s.singularize
html_options[:'data-associations'] = association.to_s.pluralize
new_object = f.object.class.reflect_on_association(association).klass.new
html_options[:'data-template'] = CGI.escapeHTML(render_association(association, f, new_object)).html_safe
link_to(name, '#', html_options )
end
end
Thanks for your help in advance.

You could do that using JavaScript and Cocoon helper method before and after insert. So what you could do
.bind('cocoon:after-insert', function() {
/* ...
1. check to see if the number of nested fields added is equal to what you want
2. if it is equal, hide the link_to_add_association link
... */
})

Related

is there any way that can offset from specific record when using scope

i have a lot of methods that look for records after specific active record. examples are:
def photo_recent
offsetphoto = Photo.find(params[:id])
#photos = Photo.recent.where('created_at> ?', offsetphoto.id).limit(10)#recent is a scope using created_at
end
def photo_recent
offsetphoto = Photo.find(params[:id])
#photos = Photo.popular.where('like_count > ?', offsetphoto.like_count).limit(10)#popular is a scope using like_count
end
i was wondering if there is any way to modularize this such as:
#photos = Photo.recent.offset(Photo.find(params[:id])).limit(10)
# models/photo.rb
scope :most_recent_starting_from, -> (photo) { order(created_at: :asc).where('created_at >= ?', photo.created_at) }
Example Usage
photo = Photo.find(123)
ten_next_created_photos_after_photo = Photo.most_recent_starting_from(photo).limit(10)
You could write a scope that just takes everything from the current Photo
scope :offset_from, -> (photo) { where('id >= ?', photo.id) }
Photo.offset_from(Photo.find(params[:id]))......

Passing array to Rails where method

So I want to dynamically pass filter parameters to my where method so basically I have this
#colleges = College.where(#filter).order(#sort_by).paginate(:page => params[:page], :per_page => 20)
And the #where is just a string built with this method
def get_filter_parameters
if params[:action] == 'index'
table = 'colleges'
columns = College.column_names
else
table = 'housings'
columns = Housing.column_names
end
filters = params.except(:controller, :action, :id, :sort_by, :order, :page, :college_id)
filter_keys = columns & filters.keys
#filter = ""
first = true
if filter_keys
filter_keys.each do |f|
if first
#filter << "#{table}.#{f} = '#{filters[f]}'"
first = false
else
#filter << " AND #{table}.#{f} = '#{filters[f]}'"
end
end
else
#filter = "1=1"
end
The problem is I don't know how good it is to drop raw SQL into a where method like that. I know normally you can do stuff like :state => 'PA', but how do I do that dynamically?
UPDATE
Okay so I am now passing a hash and have this:
if params[:action] == 'index'
columns = College.column_names
else
columns = Housing.column_names
end
filters = params.except(:controller, :action, :id, :sort_by, :order, :page, :college_id)
filter_keys = columns & filters.keys
#filter = {}
if filter_keys
filter_keys.each do |f|
#filter[f] = filters[f]
end
end
Will that be enough to protect against injection?
in this code here:
College.where(:state => 'PA')
We are actually passing in a hash object. Meaning this is equivalent.
filter = { :state => 'PA' }
College.where(filter)
So you can build this hash object instead of a string:
table = "colleges"
field = "state"
value = "PA"
filter = {}
filter["#{table}.#{field}"] = value
filter["whatever"] = 'omg'
College.where(filter)
However, BE CAREFUL WITH THIS!
Depending on where this info is coming from, you be opening yourself up to SQL injection attacks by putting user provided strings into the fields names of your queries. When used properly, Rails will sanitize the values in your query. However, usually the column names are fixed by the application code and dont need to be sanitized. So you may be bypassing a layer of SQL injection protection by doing it this way.

How do I assign a new element of an object in Rails 3.1?

#comments = []
#preComments = Comment.where(:resource_hash => resource_hash).
sort(:created_at.desc).all
#preComments.each do |comment|
newComment = comment
u = ::User.find_by_id comment.user_id
newComment.display_name = "Some name"
if u.image_location.nil?
newComment.image_location = "defaultpic"
else
newComment.image_location = u.image_location
end
p u
#comments << newComment
p "HERE!!!!!"
end
That's my code, but I get an error saying
undefined method `display_name=' for #
So how do I assign a display_name?
Disclosure : I've never use MongoMapper
So my best bet is : just add display_name as part of the Comment schema. In models/comment.rb :
class Comment
include MongoMapper::Document
key :display_name, String
key ...
[...]
end

Rails 3 : Add some methods in models, for development

I would like to add some methods to some AR Models of my App; but I think they should only be available under some circumstances; this requires some meta-programming.
So I'd like to have a file where I put all my debug methods, the only question is where to put it?
Example, I have the models:
class Admin::Restaurant < ActiveRecord::Base
class Admin::Order < ActiveRecord::Base
And in my file I have (it does deppend on MetaWhere.operator_overload! initialization):
if Rails.env != 'production'
class Admin::Order
def self.mock_make
r = Restaurant.first
user_query = User.where( :created_at > "2011-04-01" )
u = user_query.first( :offset => ( user_query.count * rand ).to_i )
o = r.orders.new
o.user = u
o.value = rand(100) + rand.round(2)
if o.save
return o
else
return nil
end
end
end
end
The thing is.. I can't get it to work on /config/initializers or /app/models.
Wrap it as a external module and include it with if condition
class MyClass << ActiveRecord::Base
include MyExtraModule if Rails.env == 'development'
end
Put them in config/environments/development.rb

XML parsing from API with Nokogiri and Rails 3

Hi Im trying to parse XML from a websites API with Nokogiri. Im just curious to see if Im on the right track. I have a controller wich handles the parsing and then I would like the model to initialize the necessary parameters and then display it as a simple list in the view. I was thinking something like this in the Controller:
def index
doc = Nokogiri::XML(open("http://www.mysomething.com/partner/api/1_0/somerandomkeynumber4b0/channel/11number/material/list/").read)
#news = []
doc.css("news").each do |n|
header = n.css("header").text
source_name = n.css("source_name").text
summary = n.css("summary").text
url = i.css("url").text
created_at = i.css("created_at").text
type_of_media = i.css("type_of_media").text
#news << News.new(
:header => header,)
end
and then the Model:
class News
include ActiveModel::Validations
validates_presence_of :url, :type_of_media
attr_accessor :header, :source_name, :summary, :url, :created_at, :type_of_media
def initialize(attributes = {})
#header = attributes[:header]
#source_name = attributes[:source_name]
#summary = attributes[:summary]
#url = attributes[:url]
#created_at = attributes[:created_at]
#type_of_media = attributes[:type_of_media]
end
Is this how you would do this?! Not sure Im thinking correct on this. Maybe you have any tips on a great way of incorporating Nokogiri with some other thing for the view like Google maps or something. Right now Im getting an error saying
Missing template news/index with {:formats=>[:html], :handlers=>[:builder, :rjs, :erb, :rhtml, :rxml], :locale=>[:en, :en]} in view paths
Thanks in advance!
#noodle: So this:
#news = doc.css('query').map do |n|
h = {}
%w(header source_name summary url created_at type_of_media).each do |key|
h[key.to_sym] = n.css(key).text
end
News.new(h)
end
Is equal to:
#news = []
doc.css("news").each do |n|
header = n.css("header").text
source_name = n.css("source_name").text
summary = n.css("summary").text
url = i.css("url").text
created_at = i.css("created_at").text
type_of_media = i.css("type_of_media").text
#news << News.new(
:header => header,)
end
Did I understand you correctly?! Regarding the template I have located the the problem. It was a minor misspelling. Cheers!
You're really asking two questions here..
Is my xml -> parse -> populate pipeline ok?
Yes, pretty much. As there's no conditional logic in your .each block it would be cleaner to do it like this:
#news = doc.css('query').map do |n|
#...
News.new(:blah => blah, ...)
end
.. but that's a minor point.
EDIT
You could save some typing by initializing a hash from the parsed xml and then passing that to Model.new, like:
#news = doc.css('query').map do |n|
h = {}
h[:header] = n.css('header').text
# ...
News.new(h)
end
EDIT 2
Or even shorter..
#news = doc.css('query').map do |n|
h = {}
%w(header source_name summary url created_at type_of_media).each do |key|
h[key.to_sym] = n.css(key).text
end
News.new(h)
end
In fact #inject could make that shorter still but I think that'd be a little obfuscated.
Why can't rails find my view template?
Dunno, is there one? You've not given enough details to answer that part.