UPDATE regarding accessing uploaded_picture:
======>
The culprit was in ImageItem.rb where I had call to upload_picture as private. Apparently controller call with parms.require.permit is a public call to attr_accessor with before_create on that variable.
With regard to .create! and .update! this param def is working:
def item_image_params
params.require(:items).require(:item).require(:item_images).permit(:item_image_caption, :uploaded_picture)
end
===== >
Request parameters are exactly -- with regard to structure:
See below...
Parameters: {"utf8"=>"✓", "authenticity_token"=>"foo", "commit"=>"new_item",
"items"=>{"item"=>{"field_changed"=>"0", "item_type"=>"lend", "remote_ip"=>"", "item_id"=>"", "participant_id"=>"", "category_id"=>"1", "other_item_category"=>"", "item_description"=>"", "item_condition_id"=>"-2", "item_model"=>"", "item_count"=>"", "notify"=>"0", "comment"=>"", "item_images"=>{"participant_id"=>"", "item_image_id"=>"", "item_image_caption"=>""}},
"contact_preference"=>{"preference_field_changed"=>"1",
"contact_preference_id"=>"20", "item_id"=>"", "user_id"=>"19", "participant_id"=>"899", "use_which_contact_address"=>"0", "contact_by_chat"=>"0", "contact_by_email"=>"0", "contact_by_home_phone"=>"0", "contact_by_Facebook"=>"foo", "contact_by_LinkedIn"=>"foo", "contact_by_Twitter"=>"foo", "contact_by_Instagram"=>"foo", "contact_by_other_social_media"=>"1", "contact_by_other_social_media_access"=>"2"},
"lender_transfer"=>{"transfer_field_changed"=>"0", "lender_transfer_id"=>"foo", "item_id"=>"", "remote_ip"=>"", "participant_id"=>"foo", "user_id"=>"19", "borrower_comes_to_which_address"=>"3", "meetBorrowerAtAgreed"=>"0", "meetBorrowerAtAgreedBorrowerChoice"=>"0", "meetBorrowerAtAgreedMutual"=>"0", "thirdPartyPresenceMutual"=>"1", "borrower_returns_to_which_address"=>"3", "willPickUpPreferredLocation"=>"0", "comment"=>"fgfg"},
"lender_item_condition"=>{"condition_field_changed"=>"0", "lender_item_condition_id"=>"1", "item_id"=>"", "remote_ip"=>"", "participant_id"=>"foo", "user_id"=>"19", "small_fee_amount"=>"12.0", "available_for_purchase_amount"=>"", "trade_item"=>"12", "security_deposit_amount"=>"", "specific_conditions"=>"1221"}}, "id"=>"foo"}
This is not working:
def contact_preference_params
params.require(:contact_preference).permit(:item_id, :user_id, :use_which_contact_address,
:contact_by_chat, :contact_by_email, :contact_by_home_phone, :contact_by_cell_phone,
:contact_by_alternative_phone, :contact_by_Facebook, :contact_by_Twitter, :contact_by_Instagram,
:contact_by_LinkedIn, :contact_by_other_social_media, :contact_by_other_social_media_access)
end
Nor this:
def contact_preference_params
params.require(:items).require(:contact_preference).permit(:item_id, :user_id, :use_which_contact_address,
:contact_by_chat, :contact_by_email, :contact_by_home_phone, :contact_by_cell_phone,
:contact_by_alternative_phone, :contact_by_Facebook, :contact_by_Twitter, :contact_by_Instagram,
:contact_by_LinkedIn, :contact_by_other_social_media, :contact_by_other_social_media_access)
end
def contact_preference_params called from:
def update_cp
#pid = params[:items][:item][:participant_id]
#item_id = params[:items][:contact_preference][:item_id]
#current_item = nil
if #item_id.nil?
#current_item = ContactPreference.create!(contact_preference_params)
else
#cp = ContactPreference.where("participant_id = :pid and item_id = :iid", {pid: #pid, iid: #item_id }).first
#current_item = #cp.update!(contact_preference_params)
end
#current_item
end
Discovered I had an error in def, def update_cp
What worked is:
def contact_preference_params
params.require(:items).require(:contact_preference).permit(:item_id, :user_id, :use_which_contact_address,
:contact_by_chat, :contact_by_email, :contact_by_home_phone, :contact_by_cell_phone,
:contact_by_alternative_phone, :contact_by_Facebook, :contact_by_Twitter, :contact_by_Instagram,
:contact_by_LinkedIn, :contact_by_other_social_media, :contact_by_other_social_media_access)
end
====== >> UPDATE
Discovered another problem;
ERROR: ActiveModel::UnknownAttributeError (unknown attribute 'uploaded_picture' for ItemImage.):
Request param:
Parameters: {"utf8"=>"✓", "authenticity_token"=>"", "commit"=>"new_item",
"items"=>
{"item"=>{"field_changed"=>"1", "item_type"=>"lend", "remote_ip"=>"", "item_id"=>"", "participant_id"=>"", "category_id"=>"1", "other_item_category"=>"", "item_description"=>"ghfg", "item_condition_id"=>"3", "item_model"=>"fghgf", "item_count"=>"12", "notify"=>"0", "comment"=>"fgh gfhfg fghgf",
"item_images"=>{"item_image_id"=>"", "item_id"=>"", "uploaded_picture"=>#, #original_filename="foo.jpg", #content_type="image/jpeg", #headers="Content-Disposition: form-data; name=\"items[item][item_images][uploaded_picture]\"; filename=\"1[1].jpg\"\r\nContent-Type: image/jpeg\r\n">, "item_image_caption"=>"foo"}}}, "id"=>""}
How does one access items => item => item_image => uploaded picture when uploaded_picture is an attr_acessor in model.rb
item_image.rb
class ItemImage < ApplicationRecord
belongs_to :item
attr_accessor :uploaded_picture, :item_type
before_save :uploaded_picture
private
def uploaded_picture=(picture_field)
unless (picture_field.blank?)
begin
name = self.item_id.to_s + '_' +
File.basename(picture_field.original_filename).gsub(/[^\w._-]/, '')
directory = './app/assets/images/' + self.item_type.to_s
path = File.join(directory, name)
# write the file -- b is for binary
File.open(path, "wb") { |f| f.write(picture_field.read) }
self.image_file_name = name
self.image_content_type = picture_field.content_type.chomp
self.image_width = 0
self.image_height = 0
.... end
image_image table:
Field | Type | Null | Key | Default | Extra
item_image_id | int(11) | NO | PRI | NULL | auto_increment |
|
item_id | varchar(40) |
image_content_type | varchar(20) |
image_height | int(3) |
image_width | int(3) |
image_file_name | varchar(150) |
item_image_caption | varchar(50) |
...
html.erb
...
<%= item_images.hidden_field :item_image_id %>
<%= item_images.hidden_field :item_id %>
<%= f.hidden_field :item_type, :value => #itype %>
<div style="margin-left:25px;margin-top:5px;float:left;">
<%= item_images.label :uploaded_picture, "Image of Item" %>
<%= item_images.file_field :uploaded_picture %>
<% if #ii %>
<% if #ii.image_file_name %>
<% #imageLibrary = #imageLibrary + "/" + #ii.image_file_name %>
<% end %>
<% end %>
...
ItemsController
def update_item
...
unless #current_item.nil?
#itemImageRecord = #current_item.item_images.update!(item_image_params)
else
#itemImageRecord = #current_item.item_images.create!(item_image_params)
def item_image_params
params.require(:items).require(:item).permit(:item_images).permit(:item_id, :item_type, :item_image_caption, :uploaded_picture)
end
ERROR: ActiveModel::UnknownAttributeError (unknown attribute 'uploaded_picture' for ItemImage.):
Related
Background:
I have some code (Rust) that finds (Regex) matches and assigns the found values to fields in a struct named Article (where all fields are of type String):
pub struct Article {
// user facing data
title: String,
category: String,
subcategory: String,
genre: String,
published: String,
estimated_read_time: String,
description: String,
tags: String,
keywords: String,
image: String,
artwork_credit: String,
// meta data
metas: String,
// location
path: String,
slug: String,
// file data
content: String
}
A regular expression ("//\- define (.*?): (.*?)\n") is used to extract comments from the article's template that define data for that article:
// iterate through HTML property pattern matches
for capture in re_define.captures_iter(&file_content as &str) {
// remove the declaration from the the HTML output
article_content = article_content.replace(&capture[0].to_string(), "");
// get the property value
let property_value: &String = &capture[2].to_string();
// determine what field to assign the property to and assign it
match capture[1].to_lowercase().as_str() {
"title" => article.title = property_value.clone(),
"category" => article.category = property_value.clone(),
"subcategory" => article.subcategory = property_value.clone(),
"genre" => article.genre = property_value.clone(),
"published" => article.published = property_value.clone(),
"estimated_read_time" => article.estimated_read_time = property_value.clone(),
"description" => article.description = property_value.clone(),
"tags" => article.tags = property_value.clone(),
"keywords" => article.keywords = property_value.clone(),
"image" => article.image = property_value.clone(),
unknown_property # _ => {
println!("Ignoring unknown property: {}", &unknown_property);
}
}
}
Note: article is an instance of Article.
Issue:
The code works but what I'm concerned about the following part:
"title" => article.title = property_value.clone(),
"category" => article.category = property_value.clone(),
"subcategory" => article.subcategory = property_value.clone(),
"genre" => article.genre = property_value.clone(),
"published" => article.published = property_value.clone(),
"estimated_read_time" => article.estimated_read_time = property_value.clone(),
"description" => article.description = property_value.clone(),
"tags" => article.tags = property_value.clone(),
"keywords" => article.keywords = property_value.clone(),
"image" => article.image = property_value.clone(),
It calls .clone() on the same String (property_value) for every match (10 matches per article template), for every article template (a couple dozen templates in total), and I don't think it's the most efficient way to do it.
Note: I'm not sure if match is cloning for non-matches.
What I tried:
I tried referencing the property_value String, but I got an error for each reference.
Error from IDE (VS Code):
mismatched types
expected struct `std::string::String`, found `&&std::string::String`
expected due to the type of this binding
try using a conversion method: `(`, `).to_string()`
Error from cargo check:
error[E0308]: mismatched types
--> src/article.rs:84:38
|
84 | "image" => article.image = &property_value,
| ------------- ^^^^^^^^^^^^^^^ expected struct `std::string::String`, found `&&std::string::String`
| |
| expected due to the type of this binding
|
help: try using a conversion method
|
84 | "image" => article.image = (&property_value).to_string(),
| + +++++++++++++
I did try using .to_string(), but I'm not sure if converting a String to the same type is the most efficient to do it either.
Question:
How do I avoid calling .clone() on property_value so many times?
Going by the types, you should just be able to drop the borrow in property_value and then you don't need the .clone()s.
let property_value: &String = &capture[2].to_string();
// change to
let property_value: String = capture[2].to_string();
// or just simply
let property_value = capture[2].to_string();
I'm assuming this was added as capture[2] returns a str (non-sized type) which would require the & but with to_string() it converts to the owned type String which is fine on it's own. This wont have any performance effect as to_string() copies anyway.
I have 3 search field(event_name, event_loc, event_date), while one of them filled it return all table data, while it has to be return one.
views.py
def searchEvent(request):
if request.is_ajax():
q_event_name = request.POST.get('event_name')
q_event_loc = request.POST.get('event_loc')
q_event_date = request.POST.get('event_date')
# return JsonResponse(dict(events=list(Event.objects.values('name', 'info'))))
return JsonResponse(
serializers.serialize('json', Event.objects.filter(
Q(name__icontains=q_event_name) | Q(info__icontains=q_event_loc) | Q(start_event_dt__icontains=q_event_date))),
safe=False)
custom.js
$.ajax({
url: '/searchevent/',
data: {
'event_name': event_name,
'event_loc': event_loc,
'event_date': event_date
},
dataType: 'json',
type: 'POST',
success: function (data) {
data = JSON.parse(data);
event_html = '';
for(var i in data){
event_name = data[i]['fields']['name'];
event_html = event_html + '<div class="col-md-4">' +
' <h5 class="card-title text-center pt-3">' + event_name + '</h5>' +
'</div>';
}
document.getElementById("event-container").innerHTML = event_html;
}
});
for example, I have two event in my DB
name=aaa, loc=bbb, date=2019-01-01
name=ccc, loc=ddd, date=2018-01-01
in the search bar when I searched for only name field with aaa, it returns all of the two event, which i expected to return me only first event.
You are using Q-expressions to build up your query (or-conditions).
So your filter expression will translate to:
name__icontains=q_event_name OR info__icontains=q_event_loc OR start_event_dt__icontains=q_event_date
If q_event_loc is for example an empty string - icontains will match every info column which is not null.
I am getting in redmine Request-URI Too Long
The requested URL's length exceeds the capacity limit for this server. whenever I try to select csv in timesheet plugin to export the timesheet report.
How do i solve this please tell me
The problem is the method. You are trying to retrieve too many parameters in the url and Apache (or any other like this one) have a limit of 2000 characters by default. In my case I didnt have access to the Apache server so changing the .conf file was not an option.
Looking into the forks of the repository I found someone who has already solved this issue. Here is a link to SashaH's pull request.
This pull request is fairly new so it's not committed yet.
Just change the code as indicated and the plugin should work as you want:
app/helpers/timesheet_helper.rb
:timesheet => timesheet.to_param)
end
- def link_to_csv_export(timesheet)
- link_to('CSV',
- {
- :controller => 'timesheet',
- :action => 'report',
- :format => 'csv',
- :timesheet => timesheet.to_param
- },
- :method => 'post',
- :class => 'icon icon-timesheet')
+ def form_for_csv_export(timesheet)
+ params_like_decode_url = CGI.unescape({:timesheet => timesheet.to_param}.to_query)
+ inputs = ""
+ form = form_tag :controller => 'timesheet', :action => 'report', :format => 'csv' do
+ params_like_decode_url.split("&").each do |param|
+ param_arr = param.split("=")
+ inputs << hidden_field_tag(param_arr.first, param_arr.last, :id => "")
+ end
+ inputs << submit_tag("CSV")
+ inputs.html_safe
+ end
+ form.html_safe
end
def toggle_arrows(element, js_function)
app/models/timesheet.rb
def to_csv
out = "";
+
+ handle_time_entries = {}
+ time_entries.each do |k,v|
+ if k.is_a? String
+ handle_time_entries[k] = v
+ next;
+ end
+ handle_time_entries[k.name] = v
+ end
+
+ time_entries = handle_time_entries
FCSV.generate(out, :encoding => 'u', :force_quotes => true) do |csv|
csv << csv_header
## -314,7 +325,7 ## def time_entries_for_user(user, options={})
return TimeEntry.includes(self.includes).
where(self.conditions([user], extra_conditions)).
- order('spent_on ASC')
+ order('spent_on ASC').references(self.includes)
end
def fetch_time_entries_by_project
app/views/timesheet/report.html.erb
<div class="contextual">
- <%= link_to_csv_export(#timesheet) %>
+ <%= form_for_csv_export(#timesheet) %>
<%= permalink_to_timesheet(#timesheet) %>
</div>
init.rb
require 'redmine'
## Taken from lib/redmine.rb
-#if RUBY_VERSION < '1.9'
-# require 'faster_csv'
-#else
-# require 'csv'
-# FCSV = CSV
-#end
+if RUBY_VERSION < '1.9'
+ require 'faster_csv'
+else
+ require 'csv'
+ FCSV = CSV
+end
if Rails::VERSION::MAJOR < 3
require 'dispatcher'
I'm using counter_culture to create survey applications
the problem is each time I add citizen the count columns is not automatically update
I have to go to console and run Citizen.counter_culture_fix_counts
below is my model and controller for reference
I'm using rails 4 and nested_attributes
thank you for help
model
class Familycard < ActiveRecord::Base
has_many :citizens , :dependent => :destroy
accepts_nested_attributes_for :citizens, :allow_destroy => :true
end
class Citizen < ActiveRecord::Base
belongs_to :familycard
counter_culture :familycard,
:column_name => Proc.new { |model| "#{model.sex}_count"},
:column_names => {
["citizens.sex = ? ", 'male'] => 'males_count',
["citizens.sex = ? ", 'female'] => 'females_count'
}
counter_culture :familycard
counter_culture :familycard,
:column_name => Proc.new { |model| "#{model.job}_count"},
:column_names => {
["citizens.job = ? ", 'Entrepreneur'] => 'Entrepreneurs_count',
["citizens.job = ? ", 'House wife'] => 'housewifes_count',
["citizens.job = ? ", 'Student'] => 'students_count',
["citizens.job = ? ", 'Veteran'] => 'veterans_count',
}
end
controller
class FamilycardController < ApplicationController
def new
#familycard = Familycard.new(:citizens => [Citizen.new])
end
def create
#familycard = Familycard.new(familycard_params)
if #familycard.save
flash[:success] = "Data Saved"
redirect_to familycards_path
else
render 'familycards/familycard_form'
end
end
follow up some comments from my question, I have solved my problem above, and below are sample code for condition for the gem
counter_culture :parent_model, :column_name => Proc.new {|child_model|
if child_model.published_condition == 'CONDITION 1'
"condition1_count"
elsif child_model.published_condition == 'CONDITION 2'
"condition2_count"
elsif child_model.published_condition == 'CONDITION 3'
"condition3_count"
end
}, :column_names => {
["child_models.published_condition = ?", 'CONDITION 1'] => 'condition1_count',
["child_models.published_condition = ?", 'CONDITION 2'] => 'condition2_count',
["child_models.published_condition = ?", 'CONDITION 3'] => 'condition3_count'
}
explanation:
parent_model has 3 fields to save the total number which are condition1_count,condition2_count and condition3_count
I have the following models set up
# task.rb
class Task << AR
# everything all task objects have in common
end
# login_request.rb
class Tasks::LoginRequest < Task
store :data, accessors: [:email, :first_name, :last_name, :expires_at]
composed_of :valid_until, class_name: 'DateTime', mapping: %w(expires_at to_s), constructor: Proc.new { |date| (date && date.to_datetime) || DateTime.now }, converter: Proc.new { |value| value.to_s.to_datetime }
end
I'm using the datetime_select helper in my form:
# _form.html.haml
= f.datetime_select :valid_until
This works quite well, but when I call update in my controller with the submitted form data I get the following error message:
1 error(s) on assignment of multiparameter attributes [error on assignment [2014, 4, 2, 9, 48] to valid_until (can't write unknown attribute 'expires_at')]
So, I'm guessing the updated method tries to manipulate the attributes hash directly, but obviously it can't find the attribute expires_at, since it's a simple accessor method of the JSON column data.
I know I could simply add this field to the DB and it would probably work - although there's no need then to have a composed_of statement. But I'd rather not go this route, because not every task has a expires_at column.
How can I overcome this error? Or did I miss something?
Currently compose_of is not supporting this scenario since it writes directly to attributes that are assumed to be in the database. I wrote a tweaked compose_of version that does (based of Rails 4.0.2 version)
Putting this in initialize folder:
#/initialize/support_store_in_composed_of.rb
module ActiveRecord
module Aggregations
extend ActiveSupport::Concern
def clear_aggregation_cache #:nodoc:
#aggregation_cache.clear if persisted?
end
module ClassMethods
def composed_of_with_store_support(part_id, options = {})
options.assert_valid_keys(:class_name, :mapping, :allow_nil, :constructor, :converter, :store)
name = part_id.id2name
class_name = options[:class_name] || name.camelize
mapping = options[:mapping] || [ name, name ]
mapping = [ mapping ] unless mapping.first.is_a?(Array)
allow_nil = options[:allow_nil] || false
constructor = options[:constructor] || :new
converter = options[:converter]
reader_method(name, class_name, mapping, allow_nil, constructor, options[:store])
writer_method(name, class_name, mapping, allow_nil, converter, options[:store])
create_reflection(:composed_of, part_id, nil, options, self)
end
private
def reader_method(name, class_name, mapping, allow_nil, constructor, store=nil)
define_method(name) do
if #aggregation_cache[name].nil? && (!allow_nil || mapping.any? {|pair| !read_attribute(pair.first).nil? })
if store.present?
attrs = mapping.collect {|pair| send(pair.first)}
else
attrs = mapping.collect {|pair| read_attribute(pair.first)}
end
object = constructor.respond_to?(:call) ?
constructor.call(*attrs) :
class_name.constantize.send(constructor, *attrs)
#aggregation_cache[name] = object
end
#aggregation_cache[name]
end
end
def writer_method(name, class_name, mapping, allow_nil, converter, store=nil)
define_method("#{name}=") do |part|
klass = class_name.constantize
unless part.is_a?(klass) || converter.nil? || part.nil?
part = converter.respond_to?(:call) ? converter.call(part) : klass.send(converter, part)
end
if part.nil? && allow_nil
mapping.each { |pair| self[pair.first] = nil }
#aggregation_cache[name] = nil
else
if store.present?
mapping.each { |pair| send("#{pair.first}=", part.send(pair.last)) }
else
mapping.each { |pair| self[pair.first] = part.send(pair.last) }
end
#aggregation_cache[name] = part.freeze
end
end
end
end
end
end
And using it like this would solve your problem.
class Task < ActiveRecord::Base
store :data, accessors: [:email, :first_name, :last_name, :expires_at]
composed_of_with_store_support :valid_until, class_name: 'DateTime', mapping: %w(expires_at to_s),
constructor: Proc.new { |date| (date && date.to_datetime) || DateTime.now },
converter: Proc.new { |value| value.to_s.to_datetime },
store: true
end