I have the following associations
Group:
has_many :group_links, :dependent => :destroy
GroupLink:
belongs_to :group
I want to display all the group links which belong to a particular group inside a layout which includes other objects which are not visible from inside GroupLInks views. SO I want to render a template from the GroupController as follows:
def group_links
#group_links = #group.group_links.all
render :template => 'group_links/group_links', :layout =>
'/layouts/sponsored_group_manage_sub_menu'
end
But I get the following error:
The action 'index' could not be found for GroupLinksController
If I create a 'index' view for GroupLinks and try to display it inside a layout with other objects, it throws the error
"You have a nil object"
I have the following method to initialize inside my groupscontroller:
def init_group
#group = Group.find_by_id(params[:id])
#group_blog_tags=#group.blog.blog_posts.tag_counts
#booth_links = #group.group_links.all
max_id = Group.count_by_sql("select min(profile_id) from (select profile_id from
group_memberships where group_id = #{#group.id} order by profile_id desc
limit 200) as x")
#booth_members = #group.members.all(:conditions => "profiles.id >= #
{rand(max_id)+1}", :limit => 20).to_a.sort! { |a,b| rand(3)-1 }
redirect_to groups_explorations_path unless #group
end
These other objects are used in the groups layouts to display the other objects. The thing is I was able to display another object from the GroupsController, without needing any index action inside that objects Controller. I have the exact same setup for GroupLinks as well but it does not work in this case...Please can you help me resolve this?
I think the problem is that #group is nil in your controller method group_links.
You can try to make like this:
def group_links
#group = Group.find(params[:id])
#group_links = #group.group_links.all
render :template => 'group_links/group_links', :layout =>
'/layouts/sponsored_group_manage_sub_menu'
end
But I'm not sure that this will work correctly:
render :template => 'group_links/group_links', :layout =>
'/layouts/sponsored_group_manage_sub_menu'
You can try just put your template in correct view folder with name "group_links" and match in your routes.rb file.
It turns out I had not put the proper path for this method in my layout. The routes were fine but the call to this method was not - I had to break my head to find it :(...Thanks for your time #Mosin and #RubyMan, appreciate it!
Related
essentially I have a category that you can add comments to, this category shows a lists of tasks. When You add comments you have the ability to reply to said comment, when you do so and hover the reply link you’ll see something much like:
http://localhost:3000/categories/2/category_comments/new?parent=6
We then take that id, pass it to the reply forum and then assign it to the ancestry string in the database to "nest" the reply. The problem is, the parent id is not being passed to the form. The form's hidden field is blank. Why? We can walk the path this id should take in the following code.
categories_controller
def show
#category = Category.find(params[:id])
#category_comment = #category.category_comments.build
end
This shows the comment on the category page, and passes the parent_id of the comment your replying to, to the form.
When we click reply, we trigger the category_comments#new and #create methods shown below.
category_comments_controller
def new
#category = Category.find(params[:category_id])
#category_comment = #category.category_comments.build(:parent_id => params[:parent_id])
end
def create
#category = Category.find(params[:category_id])
#category_comment = #category.category_comments.create(params[:category_comment].merge(:user_id => current_user.id))
if #category_comment.save
redirect_to project_category_path(#category.project, #category), :flash => {:success => 'Created comment'}
else
redirect_to :back, :flash => {:error => 'Could not create comment'}
end
end
update:
this is no longer a form issue it is a controller issue, dealing with passing the parent_id to the form.
Try this:
<%= link_to 'Reply', new_category_category_comment_path(#category.id, :parent_id => category_comment.id)%>
Do you have has_ancestry defined in your model? I think not having it there would be a valid explanation for this not working.
Some how this magically fixed its self. I am not sure how or what happened, but it magically works now >.>
I have this controller:
def index
#disclosures = Disclosure.where(:user_id => current_user.id)
respond_to do |format|
format.html{}
format.js{}
end
end
and with the help of the good folks at StackOverflow I am now able to get my HAML to point to the partial like this:
= render :partial => "/influencers/disclosures/shared/list"
but this partial throws and exception:
-if disclosures.empty?
.alert.alert-info
%p=(no_disclosures_message || (t "influencers.influencer_dashboard.disclosures.no_disclosures"))
%table.table.influencer-disclosures
%tbody
-disclosures.each do |disclosure|
=render "influencers/disclosures/shared/row", :disclosure => disclosure
saying that:
undefined local variable or method `disclosures' for #<#<Class:0x133ca8a58>:0x133ca25e0>
But how can this be? I just queried for that disclosures object in my controller. Any idea why this is happening and how to fix it?
Thanks!!
You need to put an # in front of disclosures. This is how the controller passes variables to the view.
-if #disclosures.empty?
and
-#disclosures.each do |disclosure|
Update
Another way to fix this is the change your render call. This will make it backwards compatible with other call sites of the same partial.
render :partial => "/influencers/disclosures/shared/list", :locals => {:disclosures => #disclosures}
I have a model, Report, that is polymorphic.
So many itens in my site may have many of it.
And i would like to have a generic controller for posting it.
Its a very simple model, has only a text message and the association.
in my routes, im doing something like
map.resources :users, :has_many => [ :reports ]
map.resources :posts, :has_many => [ :reports ]
but in my reports_controller, i would like to get the relation from with its coming from.
like:
before_filter :get_reportable
def get_reportable
reportable = *reportable_class*.find params[:reportable_id]
end
is this possible?
how could i get the reportable_class and the reportable_id?
I can get the params[:user_id] when it comes from users controller, or params[:post_id] when it comes from posts. I could do a case with all the relations, but it doesnt seem a clean solution at all...
having the polymorphic association would be the best, are there any how?
If you have a single controller that processes requests through two differing paths, then you need to make it aware of the contexts in which it will be called. You often see a lot of code that looks something like this:
before_filter :load_reportable
def load_reportable
if (params[:user_id])
#user = User.find(params[:user_id])
#reportable = #user
elsif (params[:post_id])
#post = Post.find(params[:post_id])
#reportable = #post
end
rescue ActiveRecord::RecordNotFound
render(:partial => 'not_found', :status => :not_found)
return false
end
Since you're using a polymorphic association, you may be able to do something like this instead:
before_filter :load_reportable
def load_reportable
unless (#reportable = #report.reportable)
# No parent record found
render(:partial => 'not_found', :status => :not_found)
return false
end
# Verify that the reportable relationship is expressed properly
# in the path.
if (params[:user_id])
unless (#reportable.to_param == params[:user_id])
render(:partial => 'user_not_found', :status => :not_found)
return false
end
elsif (params[:post_id])
unless (#reportable.to_param == params[:post_id])
render(:partial => 'post_not_found', :status => :not_found)
return false
end
end
end
The trouble with this approach, where you have one controller that serves two entirely different routes, is that generating error messages, such as "user not found" versus "post not found". This can be tricky to get right if you're not inheriting from a Users::BaseController, for instance.
In many cases it's easier to create two independent "reports" controllers, such as users/reports and posts/reports, where any common functionality is imported from a module. These controllers usually inherit from a base controller which performs the loading and error handling. The base controller can also establish layout, page title, etc., without having to re-implement this functionality for each sub-resources controller.
The alternative is to de-couple reports and have it run as its own controller where the relationship to the "reportable" record is mostly irrelevant.
Or try that:
before_filter :get_reportable
def get_reportable
params.each do |name, value|
if name =~ /(.+)_id$/
#reportable = $1.classify.constantize.find(value)
end
end
end
It is going through all the params and tries to find one ending with _id, then grabs that before part and finds relevant record.
I'm trying to make attributes equal predetermined values, and I'm not sure if I'm doing that efficiently with the following (in my orders controller):
def create
#order = Order.find(params[:id])
#order.price = 5.99
#order.representative = Product.find(params[:product_id]).representative
#order.shipping_location = SHIPPING_LOCATION
#order.user = current_user
respond_to do |format|
...
end
end
Is there a more efficient way to equate attributes in Rails (maybe using models)? If I'm using two different controllers, do I just repeat what I did above for the new controller?
Use before_create callback in model to assign default values.
Your code is a little off, it looks like a controller action for create, but the code reads like it's for an update.
Regardless...
You could use a parameter hash to update everything at once.
In the case where you're creating:
order_update = {:price => 5.99, :representative =>
Product.find(params[:product_id]).representative,
:shipping_location => SHIPPING_LOCATION,
:user => current_user}
#order = Order.new(order_update)
In the case where you're updating:
#order.update_attributes(order_update) #attempts to save.
Mixing it into your controller code we get:
def create
#order = Order.find(params[:id])
order_update = {:price => 5.99, :representative =>
Product.find(params[:product_id]).representative,
:shipping_location => SHIPPING_LOCATION,
:user => current_user}
respond_to do |format|
if #order.update_attributes(order_update)
# save succeeded. Redirect.
else
# save failed. Render with errors.
end
end
end
Another solution:
class Example < ActiveRecord::Base
DEFAULTS = HashWithIndifferentAccess.new(:some => 'default', :values => 'here')
def initialize(params = {})
super(DEFAULTS.merge(params))
end
end
Either use initialize and merge with params, or use an ActiveRecord hook like before_create etc.
I'd like some advice on how to best refactor this controller. The controller builds a page of zones and modules. Page has_many zones, zone has_many modules. So zones are just a cluster of modules wrapped in a container.
The problem I'm having is that some modules may have some specific queries that I don't want executed on every page, so I've had to add conditions. The conditions just test if the module is on the page, if it is the query is executed. One of the problems with this is if I add a hundred special module queries, the controller has to iterate through each one.
I think I would like to see these module condition moved out of the controller as well as all the additional custom actions. I can keep everything in this one controller, but I plan to have many apps using this controller so it could get messy.
class PagesController < ApplicationController
# GET /pages/1
# GET /pages/1.xml
# Show is the main page rendering action, page routes are aliased in routes.rb
def show
#-+-+-+-+-Core Page Queries-+-+-+-+-
#page = Page.find(params[:id])
#zones = #page.zones.find(:all, :order => 'zones.list_order ASC')
#mods = #page.mods.find(:all)
#columns = Page.columns
# restful params to influence page rendering, see routes.rb
#fragment = params[:fragment] # render single module
#cluster = params[:cluster] # render single zone
#head = params[:head] # render html, body and head
#-+-+-+-+-Page Level Json Conversions-+-+-+-+-
#metas = #page.metas ? ActiveSupport::JSON.decode(#page.metas) : nil
#javascripts = #page.javascripts ? ActiveSupport::JSON.decode(#page.javascripts) : nil
#-+-+-+-+-Module Specific Queries-+-+-+-+-
# would like to refactor this process
#mods.each do |mod|
# Reps Module Custom Queries
if mod.name == "reps"
#reps = User.find(:all, :joins => :roles, :conditions => { :roles => { :name => 'rep' } })
end
# Listing-poc Module Custom Queries
if mod.name == "listing-poc"
limit = params[:limit].to_i < 1 ? 10 : params[:limit]
PropertyEntry.update_from_listing(mod.service_url)
#properties = PropertyEntry.all(:limit => limit, :order => "city desc")
end
# Talents-index Module Custom Queries
if mod.name == "talents-index"
#talent = params[:type]
#reps = User.find(:all, :joins => :talents, :conditions => { :talents => { :name => #talent } })
end
end
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #page.to_xml( :include => { :zones => { :include => :mods } } ) }
format.json { render :json => #page.to_json }
format.css # show.css.erb, CSS dependency manager template
end
end
# for property listing ajax request
def update_properties
limit = params[:limit].to_i < 1 ? 10 : params[:limit]
offset = params[:offset]
#properties = PropertyEntry.all(:limit => limit, :offset => offset, :order => "city desc")
#render :nothing => true
end
end
So imagine a site with a hundred modules and scores of additional controller actions. I think most would agree that it would be much cleaner if I could move that code out and refactor it to behave more like a configuration.
You should check out this gem:
http://github.com/josevalim/inherited_resources/tree/master
It is very elegant, and solves all the problems you have.
I'd move your snippet-specific queries into helper methods and get them out of the controller so that the snippets themselves can execute the query via erb and kept DRY and readable via a helper. So instead of referring to #refs in your module, you can instead refer to find_all_refs or somesuch in a module and have that execute and possibly memoize the response.